예제 #1
0
//given an ID, searches the local store, DHT, and if found unmarshals the bytes into a MartiniContact
func findMartiniContact(dm *DryMartini, hashedID kademlia.ID) (MartiniContact, bool) {
	var mcBytes []byte
	var mc MartiniContact
	var err error
	var success bool

	mcBytes, success = dm.KademliaInst.ValueStore.Get(hashedID)
	if !success {
		success, _, mcBytes, err = kademlia.IterativeFind(dm.KademliaInst, hashedID, 2)
		if err != nil {
			dbg.Printf("findingMartiniContact failed. searching for key:%s. err:%s\n", ERRORS, hashedID.AsString(), err)
			return mc, false
		}
		if success {
			dbg.Printf("findMartiniContact: foundValue\n", Verbose)
		} else {
			dbg.Printf("IterativeFind failed to findvalue for key:%s\n", ERRORS, hashedID.AsString())
			return mc, false
		}
	} else {
		//dbg.Printf("found martiniContact locally. Key:%+v\n", hashedID)
	}
	err = json.Unmarshal(mcBytes, &mc)
	dbg.Printf("findMartiniContact: 'foundContact.NodeIP:%s, Port:%d\n", Verbose, mc.NodeIP, mc.NodePort)
	if err != nil {
		dbg.Printf("Error unmarshaling found MartiniContact. %s\n", ERRORS, err)
		panic(1)
	}
	return mc, true
}
예제 #2
0
//decrypts encrypted data with pathKeys
//pathKeys  are in order of closest Nodes key to furthest
func UnwrapOlivesForPath(dm *DryMartini, pathKeys []FlowIDSymmKeyPair, Data []byte) []byte {
	var err error
	var tempOlive Olive
	var decData []byte
	var theData []byte

	pathLength := len(pathKeys)

	theData = Data

	for i := 0; i < pathLength; i++ {
		//encrypt the Data (using furthest nodes key) and put it into tempOlive
		dbg.Printf("UnwrapOlivesForPath; (len(pathkey)=%d) (len(theData)=%d) decrypting USING SYMMKEY and FLOWID: %+v\n", Verbose, len(pathKeys), len(theData), pathKeys[i])
		decData = DecryptDataSymm(theData, pathKeys[i].SymmKey)

		//marshal the temp Olive
		err = json.Unmarshal(decData, &tempOlive)
		if err != nil {
			dbg.Printf("error marshalling Olive:%+v, err:%s\n", ERRORS, tempOlive, err)
			panic(1)
		}
		theData = tempOlive.Data
	}
	return theData
}
예제 #3
0
//stores dm's contactInfo in the DHT
func StoreContactInfo(dm *DryMartini) {
	var err error
	var mcBytes []byte
	var key kademlia.ID = dm.KademliaInst.ContactInfo.NodeID.SHA1Hash()
	mcBytes, err = json.Marshal(dm.myMartiniContact)
	if err != nil {
		dbg.Printf("error marshalling MartiniContact: %s\n", true, err)
	}

	var m MartiniContact
	err = json.Unmarshal(mcBytes, &m)
	if err != nil {
		dbg.Printf("error: drymartini.PrintLocalData %s\n", (err != nil), err)
	}
	dbg.Printf("Print HashMap[%s]=%+v\n", Verbose, key.AsString(), m)

	dbg.Printf("storing martiniContact:%+v %+v at ID: %x\n", Verbose, dm.myMartiniContact, mcBytes, key)
	kademlia.MakeIterativeStore(dm.KademliaInst, key, mcBytes)
	go func() {
		//republish contact info ever 4 minutes. (expire time is hardcoded at 5minutes in kademlia.rpc)
		for {
			time.Sleep(time.Duration(4) * time.Minute)
			kademlia.MakeIterativeStore(dm.KademliaInst, key, mcBytes)
		}
	}()
}
예제 #4
0
// Create a new DryMartini object with its own kademlia and RPC server
func NewDryMartini(listenStr string, keylen int) *DryMartini {
	var err error
	var s *rpc.Server
	var dm *DryMartini

	dm = new(DryMartini)

	dm.EasyNewFlowIndex = 0

	//Initialize key pair
	dm.KeyPair, err = rsa.GenerateKey(rand.Reader, keylen)
	if err != nil {
		dbg.Printf("Failed to generate key! %s", true, err)
		panic(1)
	}

	//Initialize flow struct
	dm.Bartender = make(map[UUID]MartiniPick)
	dm.Momento = make(map[UUID][]FlowIDSymmKeyPair)
	dm.MapFlowIndexToFlowID = make(map[int]FlowInfo)

	var host net.IP
	var port uint16
	host, port, err = kademlia.AddrStrToHostPort(listenStr)

	//Initialize our Kademlia
	//portStr := strconv.FormatUint(uint64(port), 10)
	//var rpcPathStr string = kademlia.RpcPath+portStr
	var rpcPathStr = "junk"
	dbg.Printf("making new Kademlia with listenStr:%s, rpcPath\n", Verbose, listenStr, rpcPathStr)

	dm.KademliaInst, s = kademlia.NewKademlia(listenStr, &rpcPathStr)
	kademlia.BucketsAsArray(dm.KademliaInst)

	//myMartiniContact <- ip, port, public key
	dm.myMartiniContact.NodeIP = host.String()
	dm.myMartiniContact.NodePort = port
	dm.myMartiniContact.PubKey = dm.KeyPair.PublicKey.N.String()
	dm.myMartiniContact.PubExp = dm.KeyPair.PublicKey.E

	dbg.Printf("NewDryMartini: making new Kademlia with NodeIP: %s. NodePort:%d\n", Verbose, dm.myMartiniContact.NodeIP, dm.myMartiniContact.NodePort)

	/*
		if Verbose {
			dbg.Printf("NodeIP: %s\n", dm.myMartiniContact.NodeIP)
			dbg.Printf("NodePort: %d\n", dm.myMartiniContact.NodePort)
			dbg.Printf("PubKey: %s\n", dm.myMartiniContact.PubKey)
			dbg.Printf("PubExp: %d\n", dm.myMartiniContact.PubKey)
		}*/
	//register
	err = s.Register(dm)
	if err != nil {
		dbg.Printf("Failed to register Drymartini! %s", true, err)
		panic(1)
	}

	return dm
}
예제 #5
0
func FindGoodPath(dm *DryMartini) (bool, int) {
	dbg.Printf("FindGoodPath: FlowIndexToFlowID map:%+v\n", Verbose, dm.MapFlowIndexToFlowID)
	for index, flowInfo := range dm.MapFlowIndexToFlowID {
		if time.Now().Before(flowInfo.expireAt) {
			dbg.Printf("FindGoodPath: returning index:%d\n", Verbose, index)
			return true, index
		}
	}
	return false, -1
}
예제 #6
0
func PrintArrayOfFoundNodes(array *[]FoundNode) {
	dbg.Printf("Print Returned Found Nodes\n", Verbose)
	if len(*array) == 0 {
		return
	}
	for i, v := range *array {
		dbg.Printf("[%d] --> %s %s %d\n", Verbose, i, v.NodeID.AsString(), v.IPAddr, v.Port)
	}
	return
}
예제 #7
0
func Printf(format string, k *Kademlia, doPrint bool, v ...interface{}) {
	if RunningTests {
		if v != nil {
			(k.log).Printf(format, v...)
		} else {
			(k.log).Printf(format)
		}
	}
	if v != nil {
		dbg.Printf(format, doPrint, v...)
	} else {
		dbg.Printf(format, doPrint)
	}
}
예제 #8
0
func NewContact(AddrStr string) Contact {
	var err error
	var nodeID ID
	var host net.IP
	var port uint16

	nodeID = NewRandomID()
	host, port, err = AddrStrToHostPort(AddrStr)

	if err != nil {
		dbg.Printf("NewContact: error parsing Address STring to host/port:%s\n", true, err)
	}
	dbg.Printf("Creating new contact %s %s\n", Verbose, nodeID.AsString(), AddrStr)
	return Contact{nodeID, host, port}
}
예제 #9
0
func sendRPCsToFoundNodes(k *Kademlia, findType int, localContact *Contact, searchID ID, slist *list.List, sentMap map[ID]bool, liveMap map[ID]bool) ([]FoundNode, []byte) {
	//var value []byte
	//log.Printf("sendRPCsToFoundNodes: Start\n")
	dbg.Printf("sendRPCsToFoundNodes: shortlist:%+v\n", Verbose, *slist)
	for e := slist.Front(); e != nil; e = e.Next() {
		dbg.Printf("foundNode:%+v\n", Verbose, *(e.Value.(*FoundNode)))
	}
	resChan := make(chan *FindStarCallResponse, slist.Len())
	var ret []FoundNode = make([]FoundNode, 0, slist.Len())
	var rpcCount int = 0
	var i int = 0

	for e := slist.Front(); e != nil; e = e.Next() {
		foundNode := e.Value.(*FoundNode)
		remote := foundNode.FoundNodeToContact()
		if sentMap[foundNode.NodeID] {
			if liveMap[foundNode.NodeID] {
				ret = append(ret, *foundNode)
			}
			i++
			continue
		}
		rpcCount++
		if findType == 1 { //FindNode
			go MakeFindNodeCall(k, remote, searchID, resChan)
		} else if findType == 2 { //FindValue
			go MakeFindValueCall(k, remote, searchID, resChan)
		}
	}
	//pull replies out of the channel
	for ; rpcCount > 0; rpcCount-- {
		findNodeResult := <-resChan
		if findNodeResult.Responded {
			k.UpdateChannel <- *findNodeResult.Responder.FoundNodeToContact()
			if 2 == findType {
				if findNodeResult.ReturnedFVRes.Value != nil {
					var nArray []FoundNode = []FoundNode{*(findNodeResult.Responder)}
					return nArray, findNodeResult.ReturnedFVRes.Value
				}
			}
			dbg.Printf("adding 'live' responder to ret list:%+v\n", Verbose, *findNodeResult.Responder)
			ret = append(ret, *findNodeResult.Responder)
			i++
		}
	}
	dbg.Printf("sendRPCsToFoundNodes returning:%+v\n", Verbose, ret)
	return ret, nil
}
예제 #10
0
func MakeMartiniPing(dm *DryMartini, remoteHost net.IP, remotePort uint16) bool {

	dbg.Printf("MakeMartiniPing %s %d\n", Verbose, remoteHost, remotePort)
	//TODO: maybe should throw in a DoJoin(dm) here?
	return kademlia.MakePingCall(dm.KademliaInst, remoteHost, remotePort)

}
예제 #11
0
func (k *Kademlia) FindValue(req FindValueRequest, res *FindValueResult) error {
	var err error
	var found bool

	//log.Printf("RPC:FindValue, from %s\n", req.Sender.NodeID.AsString())
	// TODO: Implement.
	//search for the value
	//res.Value = data[req.Key]
	//var found bool
	//res.Value, found = k.HashMap[req.Key]

	//Updated code for store handler --> seems too verbose
	res.Value, found = k.ValueStore.Get(req.Key)

	if found {
		dbg.Printf("RPC:FindValue, found value [%s:%s]\n", Verbose, req.Key.AsString(), string(res.Value))
	} else {
		res.Nodes, err = FindKClosest(k, req.Key, req.Sender.NodeID)
	}

	res.MsgID = CopyID(req.MsgID)

	//REVIEW: What kind of error can happen in this function?

	return err
}
예제 #12
0
//Call Update on Contact whenever you communicate successfully
func Update(k *Kademlia, triplet Contact) (success bool, err error) {
	var dist int
	var exists bool
	var tripletP *list.Element

	//find distance
	dist = k.ContactInfo.NodeID.Distance(triplet.NodeID)
	if -1 == dist {
		dbg.Printf("Update dist == -1 return\n", Verbose)
		return true, nil
	}

	//search kbucket and return pointer to the Triplet
	exists, tripletP = k.Buckets[dist].Search(triplet.NodeID)
	if exists {
		//move to the tail
		k.Buckets[dist].MoveToTail(tripletP)
		success = true
	} else {

		if !k.Buckets[dist].IsFull() {
			//just added to the tail
			k.Buckets[dist].AddToTail(&triplet)
			success = true
		} else {
			//log.Printf("A bucket is full! Checking...\n")
			//ping the contant at the head
			///get head
			lFront := k.Buckets[dist].l.Front()
			var remoteContact *Contact = lFront.Value.(*Contact)
			///make ping
			//log.Printf("Pinging the guy in the front of the list...\n")
			succ := MakePingCall(k, remoteContact.Host, remoteContact.Port)
			if !succ {
				//log.Printf("He failed! Replacing\n")
				//drop old
				k.Buckets[dist].Drop(lFront)
				//add new to tail
				k.Buckets[dist].AddToTail(&triplet)
				success = true
			} else {
				//log.Printf("He replied! Just ignore the new one\n")
				//ignore new
				//move the old one to the tail
				k.Buckets[dist].MoveToTail(lFront)
				success = true
			}
		}
	}
	if k.FirstKBucketStore && success {
		k.DoJoinFlag = true
		k.FirstKBucketStore = false
	}

	//REVIEW
	//Should we return any error from this function?

	return success, nil
}
예제 #13
0
//more arguments for a later time
//remoteAddr net.IP, remotePort uint16, doPing bool
func DoJoin(dm *DryMartini) bool {
	var success bool
	var secToWait time.Duration = 1

	dbg.Printf("drymartini.DoJoin()\n", Verbose)

	success = kademlia.DoJoin(dm.KademliaInst)
	if !success {
		return false
	}

	dm.DoJoinFlag = false
	dbg.Printf("doJoin in %d sec\n", Verbose, secToWait)
	time.Sleep(secToWait)

	//Store our contact information
	//TODO
	StoreContactInfo(dm)
	return true
}
예제 #14
0
func StoreHandler(k *Kademlia) (chan *PutRequest, chan *GetRequest, chan ID) {
	var puts chan *PutRequest
	var gets chan *GetRequest
	var deletes chan ID

	puts = make(chan *PutRequest)
	gets = make(chan *GetRequest)
	deletes = make(chan ID)

	go func() {
		for {
			var p *PutRequest
			var g *GetRequest
			var id ID

			select {
			case p = <-puts:
				//put
				if k.ValueStore.HashMap[p.key].expireTimer != nil {
					k.ValueStore.HashMap[p.key].expireTimer.Stop()
				}
				dbg.Printf("In put handler for store. key->%s value->%s expires->%v\n", Verbose, p.key.AsString(), p.value, p.duration)
				k.ValueStore.HashMap[p.key] = StoreItem{p.value, time.AfterFunc(p.duration, func() {
					k.ValueStore.DeleteChannel <- p.key
				}), time.Now()}
			case g = <-gets:
				//get
				var si StoreItem
				var found bool
				dbg.Printf("In get handler for Store. key->%s", Verbose, g.key.AsString())
				si, found = k.ValueStore.HashMap[g.key]
				g.ReturnChan <- &GetResponse{si.Value, found}
			case id = <-deletes:
				delete(k.ValueStore.HashMap, id)
			}
			//log.Println("StoreHandler loop end\n")
		}
	}()

	return puts, gets, deletes
}
예제 #15
0
//check our list of existing paths, to see if there are any that haven't expired. Otherwise generate a new one
func FindOrGenPath(mDM *DryMartini, minLength int, maxLength int) (bool, int) {
	var success bool
	var flowIndex int
	success, flowIndex = FindGoodPath(mDM)
	if !success {
		success, flowIndex = BarCrawl(mDM, "buildingCircuitForProxy", minLength, maxLength)
		if !success {
			dbg.Printf("there was an error building the circuit!\n", ERRORS)
		}
	}
	return success, flowIndex
}
예제 #16
0
//encrypts data with pathKeys
//pathKeys  are in order of closest Nodes key to furthest
func WrapOlivesForPath(dm *DryMartini, flowID UUID, pathKeyFlows []FlowIDSymmKeyPair, Data []byte) []byte {
	var err error
	pathLength := len(pathKeyFlows)

	//if only 1 MartiniContact exists in path, then we only construct 1 Olive..
	//but that should probably never happen, (assuming always more than 1 hop atm)
	var innerOlive Olive

	//might wanna delete this at some point, should be unneccessary. inner olive doesn't need flow id
	innerOlive.FlowID = flowID

	innerOlive.Data = Data
	//dbg.Printf("We are packaging data: %s", string(Data))

	var theData []byte
	theData, err = json.Marshal(innerOlive)
	if err != nil {
		dbg.Printf("error marshalling inner Olive:%+v\n", ERRORS, innerOlive)
		panic(1)
	}

	var tempOlive Olive
	for i := pathLength - 1; i > 0; i-- {
		//important that flowID is shifted by 1
		tempOlive.FlowID = pathKeyFlows[i].FlowID
		//encrypt the Data (using furthest nodes key) and put it into tempOlive
		tempOlive.Data = EncryptDataSymm(theData, pathKeyFlows[i].SymmKey)
		dbg.Printf("USING SYMMKEY and FLOWID: %+v\n", Verbose, pathKeyFlows[i])

		//marshal the temp Olive
		theData, err = json.Marshal(tempOlive)
		if err != nil {
			dbg.Printf("error marshalling Olive:%+v, err:%s\n", ERRORS, tempOlive, err)
			panic(1)
		}
	}
	//dbg.Printf("USING SymmKEY and FlowID: %v\n", pathKeyFlows[0])
	theData = EncryptDataSymm(theData, pathKeyFlows[0].SymmKey)
	return theData
}
예제 #17
0
//makes a DryMartini.ServeDrink call on address with the Olive data, returning success and returned data if any
func MakeSendCall(dataLump Olive, nextNodeAddrStr string) (bool, []byte) {
	var client *rpc.Client
	var err error

	dbg.Printf("MakeSendCall:: next: %s!", Verbose, nextNodeAddrStr)
	if kademlia.RunningTests == true {
		//log.Printf("Unimplemented\n")
		//panic(1)
		var nextNodePort string = strings.Split(nextNodeAddrStr, ":")[1]
		if nextNodePort == "" {
			log.Printf("error getting next port: MakeSendCall\n")
			panic(1)
		}
		var portstr string = kademlia.RpcPath + nextNodePort
		log.Printf("test MakeSendCall to rpcPath:%s\n", portstr)
		client, err = rpc.DialHTTPPath("tcp", nextNodeAddrStr, portstr)
	} else {
		client, err = rpc.DialHTTP("tcp", nextNodeAddrStr)
	}
	if err != nil {
		log.Printf("Error: MakeSendCall, DialHTTP, %s\n", err)
		return false, nil
	}

	//make rpc
	var res *ServerResp = new(ServerResp)
	var req *ServerData = new(ServerData)
	req.Sent = dataLump

	err = client.Call("DryMartini.ServeDrink", req, res)
	if err != nil {
		log.Printf("Error: SendCall, Call, %s\n", err)
		return false, nil
	}
	dbg.Printf("got SendCall response: %s:%v\n", Verbose, nextNodeAddrStr, res.Success)

	client.Close()

	return res.Success, res.Data
}
예제 #18
0
func (k *Kademlia) FindNode(req FindNodeRequest, res *FindNodeResult) error {
	var err error
	//Update(k, req.Sender)
	k.UpdateChannel <- req.Sender
	dbg.Printf("RPC: FindNode from %s ---> %s\n", Verbose, req.Sender.NodeID.AsString(), k.ContactInfo.AsString())

	res.Nodes, err = FindKClosest(k, req.NodeID, req.Sender.NodeID)

	res.MsgID = CopyID(req.NodeID)

	///REVIEW: What kind of error can happen in this function?

	return err
}
예제 #19
0
//send Data using the path info stored at FlowIndex
func SendData(dm *DryMartini, flowIndex int, data string) (response string, success bool) {
	var flowInfo FlowInfo
	var flowID UUID
	var found bool
	//map index to flowID
	flowInfo, found = dm.MapFlowIndexToFlowID[flowIndex]
	if !found {
		dbg.Printf("No map from flowIndex to flowID\n", ERRORS)
		return "", false
	} else {
		flowID = flowInfo.FlowID
		dbg.Printf("Found map from flowIndex to flowID\n", Verbose)
	}
	//wrap data
	var sendingOlive Olive

	sendingOlive.Data = WrapOlivesForPath(dm, flowID, dm.Momento[flowID], []byte(data))
	//first olive gets flowID for first node in path
	sendingOlive.FlowID = dm.Momento[flowID][0].FlowID

	var nextNodeAddrStr string = dm.Bartender[flowID].NextNodeIP + ":" + strconv.FormatUint(uint64(dm.Bartender[flowID].NextNodePort), 10)

	//make send rpc
	var encResponseData []byte
	var responseData []byte
	success, encResponseData = MakeSendCall(sendingOlive, nextNodeAddrStr)
	if !success {
		dbg.Printf("Some terrible error happened while sending\n", ERRORS)
		return "", false
	}
	//unwrap data
	responseData = UnwrapOlivesForPath(dm, dm.Momento[flowID], encResponseData)
	log.Printf("SEND REPLY: %s\n", string(responseData))

	return string(responseData), true
}
예제 #20
0
func DoHTTPRequest(r *http.Request, ctx *goproxy.ProxyCtx) (*http.Request, *http.Response) {
	var success bool
	var flowIndex int
	var response string
	success, flowIndex = drymartini.FindOrGenPath(myDryMartini, DefaultCircLength, DefaultCircLength)
	if !success {
		return r, goproxy.NewResponse(r, goproxy.ContentTypeText, http.StatusInternalServerError, "error building circuit")
	}
	response, success = drymartini.SendData(myDryMartini, flowIndex, r.URL.String())
	if !success {
		log.Printf("there was an error sending the request:%s\n", r.URL.String())
		return r, goproxy.NewResponse(r, goproxy.ContentTypeText, http.StatusInternalServerError, "error sending request")
	}
	var contentType string = http.DetectContentType([]byte(response))
	dbg.Printf("detected response as having content-type:%s\n", pVerb, contentType)
	dbg.Printf("request url was:%s\n", pVerb, r.URL.String())

	//gotta set the content-type manually, detectContentType doesn't seem to work for .css
	//kept setting it as "text/plain". there's probably a much nice way than this, whatevs. fake it til you make it
	if strings.Contains(r.URL.String(), ".css") {
		contentType = "text/css"
	}
	return r, goproxy.NewResponse(r, contentType, http.StatusOK, response)
}
예제 #21
0
func MakeStore(k *Kademlia, remoteContact *Contact, Key ID, Value []byte) bool {
	var client *rpc.Client
	var localContact *Contact
	var storeReq *StoreRequest
	var storeRes *StoreResult
	var remoteAddrStr string
	var remotePortStr string
	var err error

	localContact = &(k.ContactInfo)
	remoteAddrStr = remoteContact.Host.String() + ":" + strconv.Itoa(int(remoteContact.Port))
	dbg.Printf("MakeStore: From %s --> To %s\n", Verbose, localContact.AsString(), remoteContact.AsString())

	storeReq = new(StoreRequest)
	storeReq.MsgID = NewRandomID()
	storeReq.Sender = CopyContact(localContact)
	storeReq.Key = CopyID(Key)
	storeReq.Value = Value

	storeRes = new(StoreResult)

	remotePortStr = strconv.Itoa(int(remoteContact.Port))
	//Dial the server
	if RunningTests == true {
		//if we're running tests, need to DialHTTPPath
		var portstr string = RpcPath + remotePortStr
		client, err = rpc.DialHTTPPath("tcp", remoteAddrStr, portstr)
	} else {
		client, err = rpc.DialHTTP("tcp", remoteAddrStr)
	}
	if err != nil {
		Printf("Error: MakeStore, DialHTTP, %s\n", k, Verbose, err)
		return false
	}
	//make the rpc
	err = client.Call("Kademlia.Store", storeReq, &storeRes)
	if err != nil {
		Printf("Error: MakeStore, Call, %s\n", k, Verbose, err)
		return false
	}

	client.Close()

	//update the remote node contact information
	k.UpdateChannel <- *remoteContact

	return true
}
예제 #22
0
func pathEndAction(payload string) ([]byte, error) {
	var err error
	var responseBody []byte
	var resp *http.Response
	resp, err = http.Get(payload)
	if err != nil {
		log.Printf("error for http.get: %s\n", err)
		return responseBody, err
	}
	//log.Printf("pathEndAction response:%+v\n", resp)
	responseBody, err = ioutil.ReadAll(resp.Body)
	resp.Body.Close()
	if err != nil {
		dbg.Printf("error reading response.Body: %s\n", true, err)
	}
	return responseBody, err
}
예제 #23
0
//calls the RPC function 'CreateCircuit' on the next DryMartini in the route
func MakeCircuitCreateCall(dm *DryMartini, nextNodeAddrStr string, encryptedArray [][]byte) bool {
	var client *rpc.Client
	var err error

	dbg.Printf("MakeCircuitCreateCall: %s\n", Verbose, nextNodeAddrStr)
	if kademlia.RunningTests == true {
		//log.Printf("Unimplemented\n")
		//panic(1)
		var nextNodePort string = strings.Split(nextNodeAddrStr, ":")[1]
		if nextNodePort == "" {
			dbg.Printf("error getting next port: MakeSendCall\n", ERRORS)
			return false
		}
		var portstr string = kademlia.RpcPath + nextNodePort
		dbg.Printf("test makeCircuitCreateCall to rpcPath:%s\n", Verbose, portstr)
		client, err = rpc.DialHTTPPath("tcp", nextNodeAddrStr, portstr)
	} else {
		client, err = rpc.DialHTTP("tcp", nextNodeAddrStr)
	}
	if err != nil {
		dbg.Printf("Error: MakeCircuitCreateCall, DialHTTP, %s\n", ERRORS, err)
		return false
	}

	//make rpc
	var req *CCRequest = new(CCRequest)
	req.EncryptedData = encryptedArray
	var res *CCResponse = new(CCResponse)

	err = client.Call("DryMartini.CreateCircuit", req, res)
	if err != nil {
		dbg.Printf("Error: CreateCircuit, Call, %s\n", ERRORS, err)
		return false
	}
	dbg.Printf("got DistributeSymm response: %s:%v\n", Verbose, nextNodeAddrStr, res.Success)

	client.Close()

	return res.Success
}
예제 #24
0
//rpc function. Called when creating a Circuit. Initializes FlowID and structure at this DM (so we know what SymmKey to use when forwarding traffic later)
func (dm *DryMartini) CreateCircuit(req CCRequest, res *CCResponse) error {
	var nextNodeOlive *Olive = new(Olive)
	var sha_gen hash.Hash = sha1.New()
	var decryptedData []byte
	var err error
	var encryptedData [][]byte

	dbg.Printf("CreateCircuit, my pubKey:%s\n", Verbose, dm.myMartiniContact.PubKey)
	decryptedData, err = rsa.DecryptOAEP(sha_gen, nil, dm.KeyPair, req.EncryptedData[0], nil)
	if err != nil {
		dbg.Printf("Error: DryMartini.CreateCircuit.Decrypt( %s). IP:%s Port:%d\n", ERRORS, err, dm.myMartiniContact.NodeIP, dm.myMartiniContact.NodePort)
		res.Success = false
		return nil //Change to valid error
	}

	err = json.Unmarshal(decryptedData, nextNodeOlive)
	if err != nil {
		dbg.Printf("Error: DryMartini.CreateCircuit.Unmarshal( %s)\n", ERRORS, err)
		res.Success = false
		return nil //Change to valid error
	}

	dm.Bartender[nextNodeOlive.FlowID] = nextNodeOlive.Route
	dbg.Printf("NextNodeOlive_data:%s\n", Verbose, string(nextNodeOlive.Data))

	if len(req.EncryptedData) != 1 {
		dbg.Printf("CreateCircuit: len(%d) \n", Verbose, len(req.EncryptedData))
		encryptedData = req.EncryptedData[1:]

		var nextNodeAddrStr string = nextNodeOlive.Route.NextNodeIP + ":" + strconv.FormatUint(uint64(nextNodeOlive.Route.NextNodePort), 10)
		dbg.Printf("NextHopIs: %s\n", Verbose, nextNodeAddrStr)
		res.Success = MakeCircuitCreateCall(dm, nextNodeAddrStr, encryptedData)
	} else {
		res.Success = true
	}

	return nil
}
예제 #25
0
// SEND IT RECURSIVELY, THATS HOW BARS WORK
//rpc function. Called with wrapped Olive. Unwrap and call MakeSendCall on next address if necessary.
func (dm *DryMartini) ServeDrink(req ServerData, resp *ServerResp) error {
	var raw_data []byte
	var decolive Olive
	var currFlow UUID
	var responseData []byte
	var err error
	var symmKey UUID

	currFlow = req.Sent.FlowID
	symmKey = dm.Bartender[currFlow].SymmKey

	raw_data = DecryptDataSymm(req.Sent.Data, dm.Bartender[currFlow].SymmKey)
	if Verbose {
		log.Printf("Getting a ServeDrink call!\n")
		log.Printf("We were given olive: %+v\n", req.Sent)
		log.Printf("Will use SymmKey: %v\n", symmKey)
		log.Printf("RAW DATA: %v\n", raw_data)
		log.Printf("RAW DATA(s): %s\n", string(raw_data))
	}
	// Unmarshal the new olive
	err = json.Unmarshal(raw_data, &decolive)
	if err != nil {
		log.Printf("Unmarshal error: %s\n", err)
		resp.Success = false
		return nil
	}

	//this is the last node in the flow path
	if dm.Bartender[currFlow].NextNodeIP == "end" {
		dbg.Printf("We made it to the end!\n", Verbose)
		var payload string = string(decolive.Data)
		var marshalledOlive []byte
		var responsePayload []byte
		dbg.Printf("PAYLOAD: %s\n", Verbose, payload)
		responsePayload, err = pathEndAction(payload)
		if err != nil {
			responsePayload = []byte(fmt.Sprintf("error completing endPathAction with payload:%s", payload))
		}
		var responseOlive Olive
		//flowid already set. Don't mess
		//responseOlive.FlowID = currFlow
		//log.Printf("path end action completed: setting response:%s\n", string(responsePayload))
		responseOlive.Data = responsePayload
		marshalledOlive, err = json.Marshal(responseOlive)
		if err != nil {
			log.Printf("error marhsalling responseOlive: %s\n", err)
			resp.Success = false
			return nil
		}
		encData := EncryptDataSymm(marshalledOlive, symmKey)
		resp.Data = encData
		resp.Success = true
		return nil
	}
	//this is not the last node in the chain
	//Send the new olive!
	//TODO: End case should maybe return false? It should check for failure.
	var nextNodeAddrStr string = dm.Bartender[currFlow].NextNodeIP + ":" + strconv.FormatUint(uint64(dm.Bartender[currFlow].NextNodePort), 10)
	resp.Success, responseData = MakeSendCall(decolive, nextNodeAddrStr)
	if !resp.Success {
		log.Printf("Error: ServeDrink, MakeSendCall failed\n")
		return nil
	}

	var marshalledOlive []byte
	var responseOlive Olive
	//flowID already set. don't mess
	//responseOlive.FlowID = currFlow
	responseOlive.Data = responseData
	marshalledOlive, err = json.Marshal(responseOlive)
	if err != nil {
		log.Printf("error marhsalling responseOlive: %s\n", err)
		resp.Success = false
		return nil
	}
	encData := EncryptDataSymm(marshalledOlive, symmKey)
	resp.Data = encData
	resp.Success = true
	return nil
}
예제 #26
0
//returns array of random known-to-be-live MartiniContacts (for use as a path)
func GeneratePath(dm *DryMartini, min, max int) (mcPath []MartiniContact) {
	const safetyMax int = 50
	var err error
	//var threshold int
	//var myRand *big.Int
	var randId kademlia.ID
	var pathMap map[MartiniContact]bool = make(map[MartiniContact]bool)
	//minBig := big.NewInt(int64(min))
	//myRand, err = rand.Int(rand.Reader, big.NewInt(int64(max-min)))
	//threshold = int((minBig.Int64() + myRand.Int64()))
	mcPath = make([]MartiniContact, max)
	var safetyCounter int = 0
	for i := 0; i < max; i++ {
		var foundNodes []kademlia.FoundNode
		var success bool
		safetyCounter++
		dbg.Printf("Attempt %d to add to path (curlength %d)\n", Verbose, safetyCounter, i)
		if safetyCounter == safetyMax {
			dbg.Printf("GeneratePath failure. Made %d attempts. unable to get enough MartiniContacts to build path of length:%d\n", ERRORS, safetyMax, max)
			panic(1)
		}
		randId = kademlia.NewRandomID()
		success, foundNodes, _, err = kademlia.IterativeFind(dm.KademliaInst, randId, 1)
		if len(foundNodes) == 0 {
			dbg.Printf("GeneratePath:316. no nodes found; continueing\n", Verbose)
			i--
			continue
		}

		/*
			dbg.Printf("GeneratePath: found live nodes:\n")
			kademlia.PrintArrayOfFoundNodes(&foundNodes)
		*/

		if err != nil {
			dbg.Printf("error finding random NodeID:%s, success:%s msg:%s\n", ERRORS, randId, success, err)
			panic(1)
		}
		fuckthis, fuckingo := rand.Int(rand.Reader, big.NewInt(int64(len(foundNodes))))
		if fuckingo != nil {
			dbg.Printf("error making rand:%s\n", ERRORS, fuckingo)
		}
		index := int(fuckthis.Int64())
		var hashedID kademlia.ID = foundNodes[index].NodeID.SHA1Hash()
		dbg.Printf("generatePath: findMartiniContact for mc:%+v\n", Verbose, foundNodes[index])
		var tempMC MartiniContact
		tempMC, success = findMartiniContact(dm, hashedID)
		if !success {
			dbg.Printf("error finding MartiniContact with key:%s. err:%s\n", ERRORS, hashedID.AsString(), err)
			i--
			continue
		}
		_, alreadyInPath := pathMap[tempMC]
		if alreadyInPath {
			dbg.Printf("trying to make a circular path. skipping!\n", Verbose)
			i--
			continue
		} else {
			pathMap[tempMC] = true
			mcPath[i] = tempMC
		}
		//err = json.Unmarshal(mcBytes, &mcPath[i])
		dbg.Printf("GeneratePath path-mid-build: %+v\n", Verbose, mcPath)
	}
	return
}
예제 #27
0
//generate and prep a path for traffic through the DryMartini network. Store FlowInfo in
//DryMartini.MapFlowIndexToFlowID and return index. rdy for SendData
func BarCrawl(m *DryMartini, request string, min int, max int) (bool, int) {
	var success bool

	//Generate a path
	var chosenPath []MartiniContact
	chosenPath = GeneratePath(m, min, max)

	// Send the recursie request
	var encryptedSym [][]byte = make([][]byte, len(chosenPath))
	var jar []*Olive = make([]*Olive, len(chosenPath))
	var myFlowID UUID = NewUUID()

	//log.Printf("chosenPath: %+v\n", chosenPath)

	var i int
	var tempFlowID UUID
	// Build an array of Olives
	for i = 0; i < (len(chosenPath) - 1); i++ {
		jar[i] = new(Olive)
		//make a new UUID for each node in the circuit
		tempFlowID = NewUUID()
		jar[i].FlowID = tempFlowID

		jar[i].Data = []byte("testData_" + strconv.Itoa(i))

		// Built its martiniPick
		jar[i].Route.NextNodeIP = chosenPath[i+1].NodeIP
		jar[i].Route.NextNodePort = chosenPath[i+1].NodePort
		jar[i].Route.SymmKey = NewUUID()

		// First one?
		if i == 0 {
			jar[i].Route.PrevNodeIP = m.myMartiniContact.NodeIP
			jar[i].Route.PrevNodePort = m.myMartiniContact.NodePort
		} else {
			jar[i].Route.PrevNodeIP = chosenPath[i-1].NodeIP
			jar[i].Route.PrevNodePort = chosenPath[i-1].NodePort
		}
		//append the new SymmKeyFlowID pair to momento. so we can use this to build wrapped olive with correct flowID
		m.Momento[myFlowID] = append(m.Momento[myFlowID], FlowIDSymmKeyPair{SymmKey: jar[i].Route.SymmKey, FlowID: tempFlowID})

	}
	// Do the last one
	jar[i] = new(Olive)
	tempFlowID = NewUUID()
	jar[i].FlowID = tempFlowID
	jar[i].Route.NextNodeIP = "end"
	jar[i].Route.PrevNodeIP = chosenPath[i-1].NodeIP
	jar[i].Route.PrevNodePort = chosenPath[i-1].NodePort
	jar[i].Route.SymmKey = NewUUID()
	jar[i].Data = []byte(request)

	m.Momento[myFlowID] = append(m.Momento[myFlowID], FlowIDSymmKeyPair{SymmKey: jar[i].Route.SymmKey, FlowID: tempFlowID})

	var tempBytes []byte
	var err error
	var sha_gen hash.Hash

	//log.Printf("building jar, flowID:%s\n", flowID.AsString())
	// Encrypt everything.
	for i = 0; i < len(chosenPath); i++ {
		dbg.Printf("jar[%d]: %+v\n", Verbose, i, jar[i])
		tempBytes, err = json.Marshal(jar[i])
		if err != nil {
			dbg.Printf("Error Marhsalling Olive: %+v\n", ERRORS, jar[i])
			return false, -1
		}
		sha_gen = sha1.New()
		dbg.Printf("encrypting CC element:%s with pubkey:%s\n", Verbose, i, chosenPath[i].PubKey)
		encryptedSym[i], err = rsa.EncryptOAEP(sha_gen, rand.Reader, &(chosenPath[i].GetReadyContact().PubKey), tempBytes, nil)
		if err != nil {
			dbg.Printf("BarCrawl.EncryptOAEP %s. Payload size:%d\n", ERRORS, err, len(tempBytes))
			return false, -1
		}
		dbg.Printf("path, %d %s:%d\n", Verbose, i, chosenPath[i].NodeIP, chosenPath[i].NodePort)
	}

	//Wrap and send an Olive
	var nextNodeAddrStr string = chosenPath[0].NodeIP + ":" + strconv.FormatUint(uint64(chosenPath[0].NodePort), 10)
	success = MakeCircuitCreateCall(m, nextNodeAddrStr, encryptedSym)

	//Thing to remember locally, so we know where to send
	var ourFirstPick MartiniPick

	if success {
		m.MapFlowIndexToFlowID[m.EasyNewFlowIndex] = FlowInfo{myFlowID, time.Now().Add(time.Duration(FlowExpireTime) * time.Millisecond)}
		m.EasyNewFlowIndex++
		// Build a pick for the first hop
		ourFirstPick.NextNodeIP = chosenPath[0].NodeIP
		ourFirstPick.NextNodePort = chosenPath[0].NodePort
		m.Bartender[myFlowID] = ourFirstPick
	}

	return success, (m.EasyNewFlowIndex - 1)
}
예제 #28
0
//findType (1: findNode. 2: findValue)
func IterativeFind(k *Kademlia, searchID ID, findType int) (bool, []FoundNode, []byte, error) {
	var value []byte
	var shortList *list.List //shortlist is the list we are going to return
	var closestNode ID
	var localContact *Contact = &(k.ContactInfo)
	var sentMap map[ID]bool //map of nodes we've sent rpcs to
	var liveMap map[ID]bool //map of nodes we've gotten responses from
	var kClosestArray []FoundNode
	var err error

	dbg.Printf("IterativeFind: searchID=%s findType:%d\n", Verbose, searchID.AsString(), findType)

	shortList = list.New() //list of kConst nodes we're considering
	sentMap = make(map[ID]bool)
	liveMap = make(map[ID]bool)

	kClosestArray, err = FindKClosest(k, searchID, localContact.NodeID)

	Assert(err == nil, "Kill yourself and fix me")
	Assert(len(kClosestArray) > 0, "I don't know anyone!")

	//adds len(KClosestArray) nodes to the shortList in order
	for i := 0; (i < KConst) && (i < len(kClosestArray)); i++ {
		var newNode *FoundNode
		var newNodeDist int
		newNode = &kClosestArray[i]
		newNodeDist = newNode.NodeID.Distance(searchID)
		var e *list.Element = shortList.Front()
		for ; e != nil; e = e.Next() {
			var dist int
			dist = e.Value.(*FoundNode).NodeID.Distance(searchID)
			//if responseNode is closer than node in ShortList, add it
			if newNodeDist < dist {
				shortList.InsertBefore(newNode, e)
				//node inserted! getout
				break
			}
		}
		if e == nil {
			//node is farthest yet
			shortList.PushBack(newNode)
		}
	}

	//set closestNode to first item from shortlist
	closestNode = shortList.Front().Value.(*FoundNode).NodeID

	var stillProgress bool = true

	NodeChan := make(chan *FindStarCallResponse, AConst)
	for stillProgress {
		var i int
		stillProgress = false
		//log.Printf("in main findNode iterative loop. shortList.Len()=%d len(liveMap)=%d\n", shortList.Len(),len(liveMap))
		e := shortList.Front()
		for i = 0; i < AConst && e != nil; e = e.Next() {
			foundNodeTriplet := e.Value.(*FoundNode)
			_, inSentList := sentMap[foundNodeTriplet.NodeID]
			if inSentList {
				//don't do RPC on nodes in SentList
				//don't increment i (essentially the sentNodes counter)
				continue
			}
			//send rpc
			if findType == 1 { //FindNode
				//made MakeFindNodeCall take a channel, where it puts the result
				if RunningTests {
					Printf("makeFindNodeCall to ID=%s\n", k, Verbose, foundNodeTriplet.NodeID.AsString())
				}
				go MakeFindNodeCall(k, foundNodeTriplet.FoundNodeToContact(), searchID, NodeChan)
			} else if findType == 2 { //FindValue
				if RunningTests {
					Printf("makeFindValueCall to ID=%s\n", k, Verbose, foundNodeTriplet.NodeID.AsString())
				}
				go MakeFindValueCall(k, foundNodeTriplet.FoundNodeToContact(), searchID, NodeChan)
			} else {
				Assert(false, "Unknown case")
			}
			//put to sendList
			sentMap[foundNodeTriplet.NodeID] = true
			//e = e.Next()
			i++
			//log.Printf("iterativeFindNode Find* rpc loop end\n")
		}
		//log.Printf("iterativeFind: Made FindNodeCall on %d hosts\n", i)
		var numProbs = i

		//wait for reply
		for i = 0; i < numProbs; i++ {
			//log.Printf("IterativeFind: α loop start\n")
			var foundStarResult *FindStarCallResponse
			foundStarResult = <-NodeChan
			if RunningTests {
				Printf("IterativeFind: Reading response from: %s\n", k, Verbose, foundStarResult.Responder.NodeID.AsString())
			}
			//TODO: CRASHES IF ALL ALPHA RETURN EMPTY
			if foundStarResult.Responded {
				//Non data trash

				//Take its data
				liveMap[foundStarResult.Responder.NodeID] = true

				if findType == 1 { //FindNode
					Assert(foundStarResult.ReturnedFNRes != nil, "findStarResult Struct error in iterativeFindNode")
					addResponseNodesToSL(foundStarResult.ReturnedFNRes.Nodes, shortList, sentMap, searchID)
				} else { //FindValue
					Assert(foundStarResult.ReturnedFVRes != nil, "findStarResult Struct error in iterativeFindValue")
					//log.Printf("got response from %+v findvalue _%s_\n", foundStarResult.ReturnedFVRes, string(foundStarResult.ReturnedFVRes.Value))
					if foundStarResult.ReturnedFVRes.Value != nil {
						var nArray []FoundNode = []FoundNode{*(foundStarResult.Responder)}
						//TODO
						//When an iterativeFindValue succeeds, the initiator must store the key/value pair at the closest node seen which did not return the value.
						return true, nArray, foundStarResult.ReturnedFVRes.Value, nil
					} else {
						if RunningTests {
							Printf("Could not found value in this node", k, Verbose)
						}
					}
					addResponseNodesToSL(foundStarResult.ReturnedFVRes.Nodes, shortList, sentMap, searchID)
				}

				distance := searchID.Distance(shortList.Front().Value.(*FoundNode).NodeID)
				if distance < searchID.Distance(closestNode) {
					//log.Printf("New closest! dist:%d\n", distance)
					closestNode = foundStarResult.Responder.NodeID
					stillProgress = true
				} else {
					//closestNode didn't change, flood RPCs and prep to return
					stillProgress = false
				}
			} else {
				dbg.Printf("iterativeFind: node:%+v failed to respond, removing from shortlist\n", Verbose, foundStarResult.Responder)
				//It failed, remove it from the shortlist
				for e := shortList.Front(); e != nil; e = e.Next() {
					if e.Value.(*FoundNode).NodeID.Equals(foundStarResult.Responder.NodeID) {
						shortList.Remove(e)
						break
					}
				}
			}
			//log.Printf("IterativeFind: α loop end\n")
		}
	}
	shortArray, value := sendRPCsToFoundNodes(k, findType, localContact, searchID, shortList, sentMap, liveMap)

	if findType == 1 {
		if Verbose {
			PrintArrayOfFoundNodes(&shortArray)
		}
		return true, shortArray, value, nil
	} else if findType == 2 && value != nil {
		return true, shortArray, value, nil
	}
	//if we're here and we were looking for a value, we failed. return false and foundnodes.
	return false, shortArray, value, nil
}
예제 #29
0
//Makes a FindNodeCall on remoteContact. returns list of KClosest nodes on that contact, and the id of the remote node
//REVIEW
//George: On the ground that this should be an asynchronous call, I modified the definition of the function
//func MakeFindNodeCall(localContact *Contact, remoteContact *Contact, NodeChan chan *FindNodeCallResponse) (*FindNodeResult, bool) {
func MakeFindNodeCall(k *Kademlia, remoteContact *Contact, searchKey ID, NodeChan chan *FindStarCallResponse) {
	var fnRequest *FindNodeRequest
	var fnResult *FindNodeResult
	var remoteAddrStr string
	var remotePortStr string
	var client *rpc.Client
	var resultSet *FindStarCallResponse
	var err error
	var localContact *Contact

	localContact = &(k.ContactInfo)
	remoteAddrStr = remoteContact.Host.String() + ":" + strconv.Itoa(int(remoteContact.Port))
	dbg.Printf("MakeFindNodeCall: From %s --> To %s\n", Verbose, localContact.AsString(), remoteContact.AsString())

	fnRequest = new(FindNodeRequest)
	fnRequest.MsgID = NewRandomID()
	fnRequest.Sender = CopyContact(localContact)
	fnRequest.NodeID = CopyID(searchKey)

	fnResult = new(FindNodeResult)

	resultSet = new(FindStarCallResponse)
	resultSet.ReturnedFNRes = fnResult
	resultSet.ReturnedFVRes = nil
	resultSet.Responder = remoteContact.ContactToFoundNode()
	resultSet.Responded = false

	remotePortStr = strconv.Itoa(int(remoteContact.Port))
	//Dial the server
	if RunningTests == true {
		//if we're running tests, need to DialHTTPPath
		var portstr string = RpcPath + remotePortStr
		//log.Printf("test FindNodeCall to rpcPath:%s\n", portstr)
		client, err = rpc.DialHTTPPath("tcp", remoteAddrStr, portstr)
	} else {
		client, err = rpc.DialHTTP("tcp", remoteAddrStr)
	}
	if err != nil {
		dbg.Printf("Error: MakeFindNodeCall, DialHTTP, %s\n", Verbose, err)
		NodeChan <- resultSet
		return
	}

	err = client.Call("Kademlia.FindNode", fnRequest, &fnResult)
	if err != nil {
		Printf("Error: MakeFindNodeCall, Call, %s\n", k, Verbose, err)
		NodeChan <- resultSet
		return
	}

	//if you get any nodes update you kbuckets with them
	//Jack: REVIEW: I'm not sure if we do want to update on only
	//'heard of' nodes. Only when we make direct contact no?
	//Also look at similar block in MakeFindValueCall
	/*
		for _, node := range fnResult.Nodes {
			k.UpdateChannel <- *(node.FoundNodeToContact())
		}*/

	// Mark the result as being good
	resultSet.Responded = true

	NodeChan <- resultSet
	client.Close()

	//update the remote node contact information
	k.UpdateChannel <- *remoteContact

	return
}
예제 #30
0
//func MakeFindValue(k *Kademlia, remoteContact *Contact, Key ID, fvChan chan *FindValueCallResponse) (bool, []byte, *[]FoundNode) {
func MakeFindValueCall(k *Kademlia, remoteContact *Contact, Key ID, fvChan chan *FindStarCallResponse) {
	var findValueReq *FindValueRequest
	var findValueRes *FindValueResult
	var remoteAddrStr string
	var remotePortStr string
	var client *rpc.Client
	var localContact *Contact
	var resultSet *FindStarCallResponse
	var err error

	localContact = &(k.ContactInfo)
	remoteAddrStr = remoteContact.Host.String() + ":" + strconv.Itoa(int(remoteContact.Port))
	dbg.Printf("MakeFindValue[%s]: From %s --> To %s\n", Verbose, Key.AsString(), localContact.AsString(), remoteContact.AsString())

	findValueReq = new(FindValueRequest)
	findValueReq.MsgID = NewRandomID()
	findValueReq.Sender = CopyContact(localContact)
	findValueReq.Key = CopyID(Key)

	findValueRes = new(FindValueResult)

	resultSet = new(FindStarCallResponse)
	resultSet.ReturnedFVRes = findValueRes
	resultSet.ReturnedFNRes = nil
	resultSet.Responder = remoteContact.ContactToFoundNode()
	resultSet.Responded = false

	remotePortStr = strconv.Itoa(int(remoteContact.Port))
	//Dial the server
	if RunningTests == true {
		//if we're running tests, need to DialHTTPPath
		var portstr string = RpcPath + remotePortStr
		//log.Printf("test FindNodeValue to rpcPath:%s\n", portstr)
		client, err = rpc.DialHTTPPath("tcp", remoteAddrStr, portstr)
	} else {
		client, err = rpc.DialHTTP("tcp", remoteAddrStr)
	}
	if err != nil {
		dbg.Printf("Error: MakeFindValueCall, DialHTTP, %s\n", Verbose, err)
		fvChan <- resultSet
		return
	}

	//make rpc
	err = client.Call("Kademlia.FindValue", findValueReq, &findValueRes)
	if err != nil {
		Printf("Error: MakeFindValue, Call, %s\n", k, Verbose, err)
		fvChan <- resultSet
		return
	}

	//Mark the result as being good
	resultSet.Responded = true

	fvChan <- resultSet
	client.Close()

	//update the remote node contact information
	k.UpdateChannel <- *remoteContact

	return
}