Beispiel #1
0
func TestNodeTableInsertRemove(t *testing.T) {
	b := big.NewInt(int64(0))
	var id [20]byte
	copy(id[:], b.Bytes()[:])
	selfid := utils.NewNodeID(namespace, id)
	n := newNodeTable(50, selfid)

	ary := make([]utils.NodeID, 100)

	for i := 0; i < len(ary); i++ {
		b.Add(b, big.NewInt(int64(1)))
		var id [20]byte
		copy(id[:], b.Bytes()[:])
		node := utils.NewNodeID(namespace, id)
		ary[i] = node
	}

	for _, id := range ary {
		n.insert(utils.NodeInfo{ID: id, Addr: nil})
	}

	for _, id := range ary {
		if n.find(id) == nil {
			t.Errorf("%s not found", id.String())
		}
	}

	for _, id := range ary {
		n.remove(id)
		if n.find(id) != nil {
			t.Errorf("%s should be removed", id.String())
		}
	}
}
Beispiel #2
0
func TestRouterMessageExchange(t *testing.T) {
	logger := log.NewLogger()
	msg := "The quick brown fox jumps over the lazy dog"

	key1 := utils.GeneratePrivateKey()
	key2 := utils.GeneratePrivateKey()

	router1, err := NewRouter(key1, logger, utils.DefaultConfig)
	if err != nil {
		t.Fatal(err)
	}
	router1.Discover(utils.DefaultConfig.Bootstrap())

	router2, err := NewRouter(key2, logger, utils.DefaultConfig)
	if err != nil {
		t.Fatal(err)
	}
	router2.Discover(utils.DefaultConfig.Bootstrap())

	time.Sleep(100 * time.Millisecond)
	router1.SendMessage(utils.NewNodeID(namespace, key2.Digest()), []byte(msg))

	m, err := router2.RecvMessage()
	if err != nil {
		t.Errorf("router2: recvMessage() returns error")
	}
	if m.Node.Digest.Cmp(router1.key.Digest()) != 0 {
		t.Errorf("router2: wrong source id")
	}
	if string(m.Payload) != msg {
		t.Errorf("router2: wrong message body")
	}

	router2.SendMessage(utils.NewNodeID(namespace, router1.key.Digest()), []byte(msg))
	m, err = router1.RecvMessage()
	if err != nil {
		t.Errorf("router1: recvMessage() returns error")
	}
	if m.Node.Digest.Cmp(router2.key.Digest()) != 0 {
		t.Errorf("router1: wrong source id")
	}
	if string(m.Payload) != msg {
		t.Errorf("router1: wrong message body")
	}

	router1.Close()
	router2.Close()
}
Beispiel #3
0
func NewRouter(key *utils.PrivateKey, logger *log.Logger, config utils.Config) (*Router, error) {
	exit := make(chan int)
	listener, err := getOpenPortConn(config)
	if err != nil {
		return nil, err
	}

	logger.Info("Node ID: %s", key.Digest().String())
	logger.Info("Node Socket: %v", listener.Addr())

	ns := utils.GlobalNamespace
	id := utils.NewNodeID(ns, key.Digest())

	r := Router{
		id:       id,
		listener: listener,
		key:      key,
		sessions: make(map[utils.NodeID]*session),
		mainDht:  dht.NewDHT(10, id, id, listener.RawConn, logger),
		groupDht: make(map[utils.NodeID]*dht.DHT),

		receivedPackets: make(map[[20]byte]int),

		logger: logger,
		recv:   make(chan Message, 100),
		send:   make(chan internal.Packet, 100),
		exit:   exit,
	}

	go r.run()
	return &r, nil
}
Beispiel #4
0
func (p *DHT) StoreNodes(key string, nodes []utils.NodeInfo) {
	hash := sha1.Sum([]byte(key))
	b, err := msgpack.Marshal(nodes)
	if err != nil {
		return
	}
	c := p.newRPCCommand("store-node", map[string]interface{}{
		"key":   key,
		"value": string(b),
	})

	for _, n := range p.FindNearestNode(utils.NewNodeID(p.id.NS, hash)) {
		p.sendPacket(n.ID, c)
	}

	t := newNodeTable(p.k, p.id)
	for _, n := range nodes {
		t.insert(n)
	}

	p.kvsMutex.RLock()
	msgpack.Unmarshal([]byte(p.kvs[key]), &nodes)
	p.kvsMutex.RUnlock()
	for _, n := range nodes {
		t.insert(n)
	}

	b, err = msgpack.Marshal(t.nodes())
	if err == nil {
		p.kvsMutex.Lock()
		p.kvs[key] = string(b)
		p.kvsMutex.Unlock()
	}
}
Beispiel #5
0
func (p *DHT) StoreValue(key string, value string) {
	hash := sha1.Sum([]byte(key))
	c := p.newRPCCommand("store", map[string]interface{}{
		"key":   key,
		"value": value,
	})
	for _, n := range p.FindNearestNode(utils.NewNodeID(p.id.NS, hash)) {
		p.sendPacket(n.ID, c)
	}
}
Beispiel #6
0
func TestRouterRouteExchange(t *testing.T) {
	logger := log.NewLogger()
	msg := "The quick brown fox jumps over the lazy dog"

	key1 := utils.GeneratePrivateKey()
	key2 := utils.GeneratePrivateKey()
	key3 := utils.GeneratePrivateKey()

	router1, err := NewRouter(key1, logger, utils.DefaultConfig)
	if err != nil {
		t.Fatal(err)
	}
	defer router1.Close()
	router1.Discover(utils.DefaultConfig.Bootstrap())

	router2, err := NewRouter(key2, logger, utils.DefaultConfig)
	if err != nil {
		t.Fatal(err)
	}
	defer router2.Close()
	router2.Discover(utils.DefaultConfig.Bootstrap())

	time.Sleep(100 * time.Millisecond)
	router3, err := NewRouter(key3, logger, utils.DefaultConfig)
	if err != nil {
		t.Fatal(err)
	}
	defer router3.Close()
	addr, _ := net.ResolveUDPAddr("udp", router1.listener.Addr().String())
	router3.Discover([]net.UDPAddr{net.UDPAddr{Port: addr.Port, IP: net.ParseIP("127.0.0.1")}})

	time.Sleep(100 * time.Millisecond)
	router3.SendMessage(utils.NewNodeID(namespace, key1.Digest()), []byte(msg))

	m, err := router1.RecvMessage()
	if err != nil {
		t.Errorf("router1: recvMessage() returns error")
	}
	if m.Node.Digest.Cmp(router3.key.Digest()) != 0 {
		t.Errorf("router1: wrong source id")
	}
	if string(m.Payload) != msg {
		t.Errorf("router1: wrong message body")
	}
}
Beispiel #7
0
func (s *session) sendPubkey() error {
	data, err := msgpack.Marshal(s.lkey.PublicKey)
	if err != nil {
		return err
	}

	pkt := internal.Packet{
		Src:     utils.NewNodeID(utils.GlobalNamespace, s.lkey.Digest()),
		Type:    "pubkey",
		Payload: data,
	}

	err = s.Write(pkt)
	if err != nil {
		return err
	}
	return nil
}
Beispiel #8
0
// NewClient generates a Client with the given PrivateKey.
func NewClient(key *utils.PrivateKey, config utils.Config) (*Client, error) {
	logger := log.NewLogger()

	r, err := router.NewRouter(key, logger, config)
	if err != nil {
		return nil, err
	}

	c := &Client{
		router: r,
		readch: make(chan router.Message),
		mbuf:   newMessageBuffer(128),
		id:     utils.NewNodeID(utils.GlobalNamespace, key.Digest()),
		config: config,
		Logger: logger,
	}

	return c, nil
}
Beispiel #9
0
func (s *session) sendCommonKey() ([]byte, error) {
	var key [32]byte
	_, err := rand.Read(key[:])
	if err != nil {
		return nil, err
	}

	pkt := internal.Packet{
		Src:     utils.NewNodeID(utils.GlobalNamespace, s.lkey.Digest()),
		Type:    "key",
		Payload: key[:],
	}

	err = s.Write(pkt)
	if err != nil {
		return nil, err
	}
	return key[:], nil
}
Beispiel #10
0
func (s *session) verifyPubkey() error {
	s.conn.SetReadDeadline(time.Now().Add(time.Second * 2))
	defer s.conn.SetReadDeadline(time.Time{})
	r := msgpack.NewDecoder(s.r)
	var packet internal.Packet
	err := r.Decode(&packet)
	if err != nil {
		return err
	}
	if packet.Type == "pubkey" {
		var key utils.PublicKey
		err := msgpack.Unmarshal(packet.Payload, &key)
		if err == nil {
			id := utils.NewNodeID(utils.GlobalNamespace, key.Digest())
			if id.Digest.Cmp(packet.Src.Digest) != 0 {
				return errors.New("receive wrong public key")
			}
			s.rkey = &key
		}
	} else {
		return errors.New("receive wrong packet")
	}
	return nil
}
Beispiel #11
0
func TestRouterGroup(t *testing.T) {
	var config = utils.Config{
		P: "9200-9300",
		B: []string{
			"localhost:9200-9300",
		},
	}

	logger := log.NewLogger()

	gkey1 := utils.GeneratePrivateKey()
	gkey2 := utils.GeneratePrivateKey()

	router1, err := NewRouter(utils.GeneratePrivateKey(), logger, config)
	if err != nil {
		t.Fatal(err)
	}
	router1.Join(utils.NewNodeID(utils.GroupNamespace, gkey1.Digest()))
	defer router1.Close()

	router2, err := NewRouter(utils.GeneratePrivateKey(), logger, config)
	if err != nil {
		t.Fatal(err)
	}
	router2.Join(utils.NewNodeID(utils.GroupNamespace, gkey1.Digest()))
	defer router2.Close()

	router3, err := NewRouter(utils.GeneratePrivateKey(), logger, config)
	if err != nil {
		t.Fatal(err)
	}
	router3.Join(utils.NewNodeID(utils.GroupNamespace, gkey1.Digest()))
	defer router3.Close()

	router4, err := NewRouter(utils.GeneratePrivateKey(), logger, config)
	if err != nil {
		t.Fatal(err)
	}
	router4.Join(utils.NewNodeID(utils.GroupNamespace, gkey2.Digest()))
	defer router4.Close()

	router5, err := NewRouter(utils.GeneratePrivateKey(), logger, config)
	if err != nil {
		t.Fatal(err)
	}
	router5.Join(utils.NewNodeID(utils.GroupNamespace, gkey2.Digest()))
	defer router5.Close()

	router1.Discover(utils.DefaultConfig.Bootstrap())
	router2.Discover(utils.DefaultConfig.Bootstrap())
	router3.Discover(utils.DefaultConfig.Bootstrap())
	router4.Discover(utils.DefaultConfig.Bootstrap())
	router5.Discover(utils.DefaultConfig.Bootstrap())

	time.Sleep(100 * time.Millisecond)

	msg := "The quick brown fox jumps over the lazy dog"
	router3.SendMessage(utils.NewNodeID(utils.GroupNamespace, gkey1.Digest()), []byte(msg))

	{
		m, err := router1.RecvMessage()
		if err != nil {
			t.Errorf("router1: recvMessage() returns error")
		}
		if m.Node.Digest.Cmp(router3.key.Digest()) != 0 {
			t.Errorf("router1: wrong source id")
		}
		if string(m.Payload) != msg {
			t.Errorf("router1: wrong message body")
		}
	}

	{
		m, err := router2.RecvMessage()
		if err != nil {
			t.Errorf("router2: recvMessage() returns error")
		}
		if m.Node.Digest.Cmp(router3.key.Digest()) != 0 {
			t.Errorf("router2: wrong source id")
		}
		if string(m.Payload) != msg {
			t.Errorf("router2: wrong message body")
		}
	}
}
Beispiel #12
0
func main() {
	path := os.Getenv("TANGORPATH")
	if path == "" {
		path = os.Getenv("HOME") + "/.tangor"
	}

	config := getConfig(path)

	keyfile := flag.String("i", path+"/id_dsa", "Identity file")
	bootstrap := flag.String("b", "", "Additional bootstrap node")
	web := flag.Bool("web", false, "Open web browser")
	flag.Parse()

	color.Print("\n@{Gk} @{Yk}  tangor  @{Gk} @{|}\n\n")

	if len(*bootstrap) > 0 {
		config.B = append(config.B, *bootstrap)
	}

	key, err := getKey(*keyfile)
	if err != nil {
		color.Printf(" -> @{Rk}ERROR:@{|} %v\n", err)
		os.Exit(-1)
	}

	id := utils.NewNodeID(utils.GlobalNamespace, key.Digest())
	color.Printf("Your ID: @{Wk} %s @{|}\n\n", id.String())

	client, err := murcott.NewClient(key, config)
	if err != nil {
		panic(err)
	}
	defer client.Close()

	filename := filepath.Join(path, id.Digest.String()+".dat")
	data, err := ioutil.ReadFile(filename)
	if err == nil {
		client.UnmarshalBinary(data)
	}

	if *web {
		go webui()
		open.Run("http://localhost:3000")
	}

	exit := make(chan int)
	s := Session{cli: client}

	go func() {
		for {
			select {
			case <-exit:
				return
			case <-time.After(time.Minute):
				s.save(filename)
			}
		}
	}()

	s.bootstrap()
	s.commandLoop()
	s.save(filename)
	close(exit)
}
Beispiel #13
0
func (s *Session) commandLoop() {
	var chatID *utils.NodeID

	go func() {
		for {
			m, src, err := s.cli.Read()
			if err != nil {
				return
			}
			if msg, ok := m.(murcott.ChatMessage); ok {
				/*
					if chatID == nil {
						chatID = &src
						color.Printf("\n -> Start a chat with @{Wk} %s @{|}\n\n", src.String())
					}
				*/
				str := src.String()
				color.Printf("\r* @{Wk}%s@{|} %s\n", str[len(str)-8:], msg.Text())
				fmt.Print("* ")
			}
		}
	}()

	bio := bufio.NewReader(os.Stdin)
	for {
		if chatID == nil {
			fmt.Print("> ")
		} else {
			fmt.Print("* ")
		}
		line, _, err := bio.ReadLine()
		if err != nil {
			return
		}
		c := strings.Split(string(line), " ")
		if len(c) == 0 || c[0] == "" {
			continue
		}
		switch c[0] {
		case "/chat":
			if len(c) != 2 {
				color.Printf(" -> @{Rk}ERROR:@{|} /chat takes 1 argument\n")
			} else {
				nid, err := utils.NewNodeIDFromString(c[1])
				if err != nil {
					color.Printf(" -> @{Rk}ERROR:@{|} invalid ID\n")
				} else {
					s.cli.Join(nid)
					chatID = &nid
					color.Printf(" -> Start a chat with @{Wk} %s @{|}\n\n", nid.String())
				}
			}
		case "/add":
			if len(c) != 2 {
				color.Printf(" -> @{Rk}ERROR:@{|} /add takes 1 argument\n")
			} else {
				nid, err := utils.NewNodeIDFromString(c[1])
				if err != nil {
					color.Printf(" -> @{Rk}ERROR:@{|} invalid ID\n")
				} else {
					s.cli.Roster.Set(nid, murcott.UserProfile{})
				}
			}
		case "/mkg":
			key := utils.GeneratePrivateKey()
			id := utils.NewNodeID(utils.GroupNamespace, key.Digest())
			color.Printf("Group ID: @{Wk} %s @{|}\n\n", id.String())

		case "/stat":
			color.Printf("  * NumGoroutine() = %d\n", runtime.NumGoroutine())
			nodes := s.cli.ActiveSessions()
			color.Printf("  * active sessions (%d) *\n", len(nodes))
			for _, n := range nodes {
				color.Printf(" %v\n", n)
			}
			list := s.cli.Roster.List()
			color.Printf("  * Roster (%d) *\n", len(list))
			for _, n := range list {
				color.Printf(" %v %s \n", n, s.cli.Roster.Get(n).Nickname)
			}

		case "/end":
			if chatID != nil {
				color.Printf(" -> End current chat\n")
				s.cli.Leave(*chatID)
				chatID = nil
			}
		case "/exit", "/quit":
			color.Printf(" -> See you@{Kg}.@{Kr}.@{Ky}.@{|}\n")
			return
		case "/help":
			showHelp()
		default:
			if chatID == nil {
				color.Printf(" -> @{Rk}ERROR:@{|} unknown command\n")
				showHelp()
			} else {
				s.cli.SendMessage(*chatID, murcott.NewPlainChatMessage(string(line)))
			}
		}
	}
}
Beispiel #14
0
func (s *session) ID() utils.NodeID {
	return utils.NewNodeID(utils.GlobalNamespace, s.rkey.Digest())
}
Beispiel #15
0
func (p *DHT) ProcessPacket(b []byte, addr net.Addr) {
	var c dhtRPCCommand
	err := msgpack.Unmarshal(b, &c)
	if err != nil {
		p.logger.Error("%v", err)
		return
	}

	ns := utils.GlobalNamespace
	if !bytes.Equal(p.net.NS[:], ns[:]) && p.net.Digest.Cmp(c.Net.Digest) != 0 {
		return
	}

	if p.id.Match(c.Src) {
		return
	}

	p.table.insert(utils.NodeInfo{ID: c.Src, Addr: addr})

	switch c.Method {
	case "ping":
		p.logger.Info("%s: Receive DHT Ping from %s %v", p.id.String(), c.Src.String(), addr)
		p.sendPacket(c.Src, p.newRPCReturnCommand(c.ID, nil))

	case "find-node":
		p.logger.Info("%s: Receive DHT Find-Node from %s", p.net.String(), c.Src.String())
		if id, ok := c.Args["id"].(string); ok {
			args := map[string]interface{}{}
			nid, err := utils.NewNodeIDFromBytes([]byte(id))
			if err != nil {
				p.logger.Error("find-node: %v", err)
			} else {
				nodes := append(p.table.nearestNodes(nid), p.groupTable.nearestNodes(nid)...)
				args["nodes"] = nodes
				p.sendPacket(c.Src, p.newRPCReturnCommand(c.ID, args))
			}
		}

	case "store":
		p.logger.Info("%s: Receive DHT Store from %s", p.id.String(), c.Src.String())
		if key, ok := c.Args["key"].(string); ok {
			if val, ok := c.Args["value"].(string); ok {
				p.kvsMutex.Lock()
				p.kvs[key] = val
				p.kvsMutex.Unlock()
			}
		}

	case "store-node":
		p.logger.Info("%s: Receive DHT Store-node from %s", p.id.String(), c.Src.String())
		if key, ok := c.Args["key"].(string); ok {
			if val, ok := c.Args["value"].(string); ok {

				var nodes []utils.NodeInfo
				t := newNodeTable(p.k, p.id)

				p.kvsMutex.RLock()
				msgpack.Unmarshal([]byte(p.kvs[key]), &nodes)
				p.kvsMutex.RUnlock()
				for _, n := range nodes {
					t.insert(n)
				}

				msgpack.Unmarshal([]byte(val), &nodes)
				for _, n := range nodes {
					host, port, _ := net.SplitHostPort(n.Addr.String())
					if !net.ParseIP(host).IsGlobalUnicast() {
						host, _, _ := net.SplitHostPort(addr.String())
						global, _ := net.ResolveUDPAddr(n.Addr.Network(), net.JoinHostPort(host, port))
						n.Addr = global
					}
					t.insert(n)
				}

				b, err := msgpack.Marshal(t.nodes())
				if err == nil {
					p.kvsMutex.Lock()
					p.kvs[key] = string(b)
					p.kvsMutex.Unlock()
				}
			}
		}

	case "find-value":
		p.logger.Info("%s: Receive DHT Find-Value from %s", p.id.String(), c.Src.String())
		if key, ok := c.Args["key"].(string); ok {
			args := map[string]interface{}{}
			p.kvsMutex.RLock()
			if val, ok := p.kvs[key]; ok {
				args["value"] = val
			} else {
				hash := sha1.Sum([]byte(key))
				n := p.table.nearestNodes(utils.NewNodeID(c.Src.NS, hash))
				args["nodes"] = n
			}
			p.kvsMutex.RUnlock()
			p.sendPacket(c.Src, p.newRPCReturnCommand(c.ID, args))
		}

	case "": // callback
		id := string(c.ID)
		p.chmapMutex.Lock()
		defer p.chmapMutex.Unlock()
		if ch, ok := p.chmap[id]; ok {
			delete(p.chmap, id)
			ch <- dhtRPCReturn{command: c, addr: addr}
		}
	}
}
Beispiel #16
0
func (p *DHT) LoadValue(key string) *string {
	p.kvsMutex.RLock()
	if v, ok := p.kvs[key]; ok {
		p.kvsMutex.RUnlock()
		return &v
	}
	p.kvsMutex.RUnlock()

	hash := sha1.Sum([]byte(key))
	keyid := utils.NewNodeID(p.id.NS, hash)

	retch := make(chan *string, 2)
	reqch := make(chan utils.NodeID, 100)
	endch := make(chan struct{}, 100)

	nodes := p.table.nearestNodes(keyid)

	f := func(id utils.NodeID, keyid utils.NodeID, command dhtRPCCommand) {
		ret, err := p.sendAndWaitPacket(id, command)
		if err == nil {
			if val, ok := ret.command.Args["value"].(string); ok {
				retch <- &val
			} else if _, ok := ret.command.Args["nodes"]; ok {
				var nodes []utils.NodeInfo
				ret.command.getArgs("nodes", &nodes)
				dist := id.Digest.Xor(keyid.Digest)
				for _, n := range nodes {
					p.table.insert(n)
					if dist.Cmp(n.ID.Digest.Xor(keyid.Digest)) == 1 {
						reqch <- n.ID
					}
				}
			}
		}
		endch <- struct{}{}
	}

	if len(nodes) == 0 {
		return nil
	}

	for _, n := range nodes {
		reqch <- n.ID
	}

	count := 0
	requested := make(map[utils.NodeID]struct{})

	for {
		select {
		case id := <-reqch:
			if _, ok := requested[id]; !ok {
				requested[id] = struct{}{}
				c := p.newRPCCommand("find-value", map[string]interface{}{
					"key": key,
				})
				go f(id, keyid, c)
				count++
			}
		case <-endch:
			count--
			if count == 0 {
				select {
				case data := <-retch:
					return data
				default:
					return nil
				}
			}
		case data := <-retch:
			return data
		default:
		}
	}
}