Check-in [0105d215ce]
Not logged in
Overview
Comment:Massive_Array_of_Internet_Disks Safe MaidSafe + Rust
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 0105d215ce4680fc1c637f0d36a91f396845f761
User & Date: martin_vahi on 2017-03-22 04:01:30
Other Links: manifest | tags
Context
2017-05-16 00:49
wiki references check-in: 58fe99e749 user: martin_vahi tags: trunk
2017-03-22 04:01
Massive_Array_of_Internet_Disks Safe MaidSafe + Rust check-in: 0105d215ce user: martin_vahi tags: trunk
2017-03-14 05:29
BSD -> MIT check-in: e1fbe131b4 user: martin_vahi tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Added wiki_references/2017/software/MaidSafe_net/COMMENTS.txt version [1e6791f05d].

















>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8

Related pages:

    https://www.maidsafe.net/
    https://safenetforum.org/
    https://github.com/maidsafe
    https://blog.maidsafe.net/

Added wiki_references/2017/software/MaidSafe_net/doc/2017_03_21_wget_copy_of_blog_maidsafe_net.tar.xz version [f794087c7f].

cannot compute difference between binary files

Added wiki_references/2017/software/MaidSafe_net/doc/2017_03_21_wget_copy_of_maidsafe_net.tar.xz version [3e92481bc0].

cannot compute difference between binary files

Added wiki_references/2017/software/MaidSafe_net/src_from_GitHub/pull_new_version_from_git_repository.bash version [eca87c8b96].





























































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
#!/usr/bin/env bash
#==========================================================================
# Initial author: Martin.Vahi@softf1.com
# This file is in public domain.
#==========================================================================
S_FP_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
#--------------------------------------------------------------------------
# For copy-pasting to the ~/.bashrc
#
#     alias mmmv_cre_git_clone="cp $PATH_TO_THE<$S_FP_DIR>/pull_new_version_from_git_repository ./; mkdir -p ./the_repository_clones;"
#
#--------------------------------------------------------------------------


fun_assert_exists_on_path_t1 () {
    local S_NAME_OF_THE_EXECUTABLE=$1 # first function argument
    local S_TMP_0="\`which $S_NAME_OF_THE_EXECUTABLE 2>/dev/null\`"
    local S_TMP_1=""
    local S_TMP_2="S_TMP_1=$S_TMP_0"
    eval ${S_TMP_2}
    if [ "$S_TMP_1" == "" ] ; then
        echo ""
        echo "This bash script requires the \"$S_NAME_OF_THE_EXECUTABLE\" to be on the PATH."
        echo ""
        exit 1 # exit with error
    fi
} # fun_assert_exists_on_path_t1

fun_assert_exists_on_path_t1 "ruby"
fun_assert_exists_on_path_t1 "grep"
fun_assert_exists_on_path_t1 "date"
fun_assert_exists_on_path_t1 "git"


#--------------------------------------------------------------------------
S_TMP_0="`uname -a | grep -E [Ll]inux`"
if [ "$S_TMP_0" == "" ]; then
    S_TMP_0="`uname -a | grep -E [Bb][Ss][Dd]`"
    if [ "$S_TMP_0" == "" ]; then
        echo ""
        echo "  The classical command line utilities at "
        echo "  different operating systems, for example, Linux and BSD,"
        echo "  differ. This script is designed to run only on Linux and BSD."
        echo "  If You are willing to risk that some of Your data "
        echo "  is deleted and/or Your operating system instance"
        echo "  becomes permanently flawed, to the point that "
        echo "  it will not even boot, then You may edit the Bash script that "
        echo "  displays this error message by modifying the test that "
        echo "  checks for the operating system type."
        echo ""
        echo "  If You do decide to edit this Bash script, then "
        echo "  a recommendation is to test Your modifications "
        echo "  within a virtual machine or, if virtual machines are not"
        echo "  an option, as some new operating system user that does not have "
        echo "  any access to the vital data/files."
        echo "  GUID=='797ff846-d1c1-464d-a13b-e211306131e7'"
        echo ""
        echo "  Aborting script without doing anything."
        echo ""
        exit 1 # exit with error
    fi
fi


#--------------------------------------------------------------------------

S_TIMESTAMP="`date +%Y`_`date +%m`_`date +%d`_T_`date +%H`h_`date +%M`min_`date +%S`s"
S_FP_ARCHIVE="$S_FP_DIR/archives/$S_TIMESTAMP"
S_FP_THE_REPOSITORY_CLONES="$S_FP_DIR/the_repository_clones"
mkdir -p $S_FP_THE_REPOSITORY_CLONES

#--------------------------------------------------------------------------
S_ARGV_0="$1"
SB_SKIP_ARCHIVING="f"

fun_init_sb_archive_and_archives_folder(){
    #--------
    if [ "$S_ARGV_0" == "skip_archiving" ]; then 
        SB_SKIP_ARCHIVING="t"
    fi
    if [ "$S_ARGV_0" == "ska" ]; then # abbreviation of "skip archiving"
        SB_SKIP_ARCHIVING="t"
    fi
    #--------
    if [ "$SB_SKIP_ARCHIVING" != "t" ]; then 
        mkdir -p $S_FP_ARCHIVE
    fi
    #--------
} # fun_init_sb_archive_and_archives_folder

fun_init_sb_archive_and_archives_folder

#--------------------------------------------------------------------------

AR_REPO_FOLDER_NAMES=()

fun_assemble_array_of_repository_clone_folder_names () {
    cd $S_FP_THE_REPOSITORY_CLONES
    local S_TMP_0="`ruby -e \"ar=Array.new; Dir.glob('*').each{|x| if File.directory? x then ar<<x end}; puts(ar.to_s.gsub('[','(').gsub(']',')').gsub(',',' '))\"`"
    cd $S_FP_DIR
    local S_TMP_1="AR_REPO_FOLDER_NAMES=$S_TMP_0"
    eval ${S_TMP_1}
} # fun_assemble_array_of_repository_clone_folder_names 

fun_assemble_array_of_repository_clone_folder_names 


fun_update () {
    #--------
    local S_FP_FUNC_UPDATE_ORIG="`pwd`"
    #--------
    for s_iter in ${AR_REPO_FOLDER_NAMES[@]}; do
         S_FOLDER_NAME_OF_THE_LOCAL_COPY="$s_iter"
         echo ""
         #----
         if [ "$SB_SKIP_ARCHIVING" != "t" ]; then 
             echo "            Archiving a copy of $S_FOLDER_NAME_OF_THE_LOCAL_COPY"
             cp -f -R $S_FP_THE_REPOSITORY_CLONES/$S_FOLDER_NAME_OF_THE_LOCAL_COPY $S_FP_ARCHIVE/
         else
             echo "            Skipping the archiving a copy of $S_FOLDER_NAME_OF_THE_LOCAL_COPY"
         fi
         #----
         cd $S_FP_THE_REPOSITORY_CLONES/$S_FOLDER_NAME_OF_THE_LOCAL_COPY
         echo "Checking out a newer version of $S_FOLDER_NAME_OF_THE_LOCAL_COPY"
         #--------
         # Downloads the newest version of the software to that folder.
         git checkout --force # overwrites local changes, like the "svn co"
         git pull --all --recurse-submodules --force # gets the submodules
         #----
         # http://stackoverflow.com/questions/1030169/easy-way-pull-latest-of-all-submodules
         git submodule update --init --recursive --force
         #--------
         cd $S_FP_DIR
    done
    cd $S_FP_FUNC_UPDATE_ORIG
} # fun_update 

fun_update # is a call to the function
echo ""

#==========================================================================

Added wiki_references/2017/software/MaidSafe_net/src_from_GitHub/the_repository_clones/MaidSafe-DHT/.git/FETCH_HEAD version [18e8fa6a59].

















>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
49d939bc678a37e05f67ad5863488e59b61616da		branch 'master' of https://github.com/maidsafe/MaidSafe-DHT
0acc4cb830204c9d030d2edefd68a7d4319d7248	not-for-merge	branch 'cppcheck' of https://github.com/maidsafe/MaidSafe-DHT
dbfb8bde2d024e9753cb9040b5107624e4a19299	not-for-merge	branch 'gh-pages' of https://github.com/maidsafe/MaidSafe-DHT
98bd589d4fbcaa603999d0a8868dfc2d5ad46e8b	not-for-merge	branch 'nat_detection' of https://github.com/maidsafe/MaidSafe-DHT
01deb2cf9ff5eae99766bb4ca5e7fafc34023d8f	not-for-merge	branch 'next' of https://github.com/maidsafe/MaidSafe-DHT
bb9d92802720c4b26b77d6c014dbbfedb6a9a5ec	not-for-merge	branch 'nodes_explorer' of https://github.com/maidsafe/MaidSafe-DHT
a606b471481d71f62110ee98a0c3862e2ff28a26	not-for-merge	branch 'remove_fw_declares' of https://github.com/maidsafe/MaidSafe-DHT
759293b75b14353a942cfd62e9bd52438ef774a7	not-for-merge	branch 'using_rudp' of https://github.com/maidsafe/MaidSafe-DHT

Added wiki_references/2017/software/MaidSafe_net/src_from_GitHub/the_repository_clones/MaidSafe-DHT/.git/HEAD version [acbaef275e].



>
1
ref: refs/heads/master

Added wiki_references/2017/software/MaidSafe_net/src_from_GitHub/the_repository_clones/MaidSafe-DHT/.git/ORIG_HEAD version [e88be7dbc0].



>
1
49d939bc678a37e05f67ad5863488e59b61616da

Added wiki_references/2017/software/MaidSafe_net/src_from_GitHub/the_repository_clones/MaidSafe-DHT/.git/config version [42b3278579].























>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
[core]
	repositoryformatversion = 0
	filemode = true
	bare = false
	logallrefupdates = true
[remote "origin"]
	url = https://github.com/maidsafe/MaidSafe-DHT.git
	fetch = +refs/heads/*:refs/remotes/origin/*
[branch "master"]
	remote = origin
	merge = refs/heads/master

Added wiki_references/2017/software/MaidSafe_net/src_from_GitHub/the_repository_clones/MaidSafe-DHT/.git/description version [9635f1b7e1].



>
1
Unnamed repository; edit this file 'description' to name the repository.

Added wiki_references/2017/software/MaidSafe_net/src_from_GitHub/the_repository_clones/MaidSafe-DHT/.git/hooks/applypatch-msg.sample version [86b9655a9e].































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#!/bin/sh
#
# An example hook script to check the commit log message taken by
# applypatch from an e-mail message.
#
# The hook should exit with non-zero status after issuing an
# appropriate message if it wants to stop the commit.  The hook is
# allowed to edit the commit message file.
#
# To enable this hook, rename this file to "applypatch-msg".

. git-sh-setup
test -x "$GIT_DIR/hooks/commit-msg" &&
	exec "$GIT_DIR/hooks/commit-msg" ${1+"$@"}
:

Added wiki_references/2017/software/MaidSafe_net/src_from_GitHub/the_repository_clones/MaidSafe-DHT/.git/hooks/commit-msg.sample version [ee1ed5aad9].

















































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#!/bin/sh
#
# An example hook script to check the commit log message.
# Called by "git commit" with one argument, the name of the file
# that has the commit message.  The hook should exit with non-zero
# status after issuing an appropriate message if it wants to stop the
# commit.  The hook is allowed to edit the commit message file.
#
# To enable this hook, rename this file to "commit-msg".

# Uncomment the below to add a Signed-off-by line to the message.
# Doing this in a hook is a bad idea in general, but the prepare-commit-msg
# hook is more suited to it.
#
# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p')
# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1"

# This example catches duplicate Signed-off-by lines.

test "" = "$(grep '^Signed-off-by: ' "$1" |
	 sort | uniq -c | sed -e '/^[ 	]*1[ 	]/d')" || {
	echo >&2 Duplicate Signed-off-by lines.
	exit 1
}

Added wiki_references/2017/software/MaidSafe_net/src_from_GitHub/the_repository_clones/MaidSafe-DHT/.git/hooks/post-update.sample version [b614c2f63d].

















>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
#!/bin/sh
#
# An example hook script to prepare a packed repository for use over
# dumb transports.
#
# To enable this hook, rename this file to "post-update".

exec git update-server-info

Added wiki_references/2017/software/MaidSafe_net/src_from_GitHub/the_repository_clones/MaidSafe-DHT/.git/hooks/pre-applypatch.sample version [42fa415649].





























>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#!/bin/sh
#
# An example hook script to verify what is about to be committed
# by applypatch from an e-mail message.
#
# The hook should exit with non-zero status after issuing an
# appropriate message if it wants to stop the commit.
#
# To enable this hook, rename this file to "pre-applypatch".

. git-sh-setup
test -x "$GIT_DIR/hooks/pre-commit" &&
	exec "$GIT_DIR/hooks/pre-commit" ${1+"$@"}
:

Added wiki_references/2017/software/MaidSafe_net/src_from_GitHub/the_repository_clones/MaidSafe-DHT/.git/hooks/pre-commit.sample version [36aed8976d].



































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#!/bin/sh
#
# An example hook script to verify what is about to be committed.
# Called by "git commit" with no arguments.  The hook should
# exit with non-zero status after issuing an appropriate message if
# it wants to stop the commit.
#
# To enable this hook, rename this file to "pre-commit".

if git rev-parse --verify HEAD >/dev/null 2>&1
then
	against=HEAD
else
	# Initial commit: diff against an empty tree object
	against=4b825dc642cb6eb9a060e54bf8d69288fbee4904
fi

# If you want to allow non-ASCII filenames set this variable to true.
allownonascii=$(git config --bool hooks.allownonascii)

# Redirect output to stderr.
exec 1>&2

# Cross platform projects tend to avoid non-ASCII filenames; prevent
# them from being added to the repository. We exploit the fact that the
# printable range starts at the space character and ends with tilde.
if [ "$allownonascii" != "true" ] &&
	# Note that the use of brackets around a tr range is ok here, (it's
	# even required, for portability to Solaris 10's /usr/bin/tr), since
	# the square bracket bytes happen to fall in the designated range.
	test $(git diff --cached --name-only --diff-filter=A -z $against |
	  LC_ALL=C tr -d '[ -~]\0' | wc -c) != 0
then
	cat <<\EOF
Error: Attempt to add a non-ASCII file name.

This can cause problems if you want to work with people on other platforms.

To be portable it is advisable to rename the file.

If you know what you are doing you can disable this check using:

  git config hooks.allownonascii true
EOF
	exit 1
fi

# If there are whitespace errors, print the offending file names and fail.
exec git diff-index --check --cached $against --

Added wiki_references/2017/software/MaidSafe_net/src_from_GitHub/the_repository_clones/MaidSafe-DHT/.git/hooks/pre-push.sample version [b4ad74c989].













































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#!/bin/sh

# An example hook script to verify what is about to be pushed.  Called by "git
# push" after it has checked the remote status, but before anything has been
# pushed.  If this script exits with a non-zero status nothing will be pushed.
#
# This hook is called with the following parameters:
#
# $1 -- Name of the remote to which the push is being done
# $2 -- URL to which the push is being done
#
# If pushing without using a named remote those arguments will be equal.
#
# Information about the commits which are being pushed is supplied as lines to
# the standard input in the form:
#
#   <local ref> <local sha1> <remote ref> <remote sha1>
#
# This sample shows how to prevent push of commits where the log message starts
# with "WIP" (work in progress).

remote="$1"
url="$2"

z40=0000000000000000000000000000000000000000

IFS=' '
while read local_ref local_sha remote_ref remote_sha
do
	if [ "$local_sha" = $z40 ]
	then
		# Handle delete
		:
	else
		if [ "$remote_sha" = $z40 ]
		then
			# New branch, examine all commits
			range="$local_sha"
		else
			# Update to existing branch, examine new commits
			range="$remote_sha..$local_sha"
		fi

		# Check for WIP commit
		commit=`git rev-list -n 1 --grep '^WIP' "$range"`
		if [ -n "$commit" ]
		then
			echo "Found WIP commit in $local_ref, not pushing"
			exit 1
		fi
	fi
done

exit 0

Added wiki_references/2017/software/MaidSafe_net/src_from_GitHub/the_repository_clones/MaidSafe-DHT/.git/hooks/pre-rebase.sample version [5885a56ab4].



















































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
#!/bin/sh
#
# Copyright (c) 2006, 2008 Junio C Hamano
#
# The "pre-rebase" hook is run just before "git rebase" starts doing
# its job, and can prevent the command from running by exiting with
# non-zero status.
#
# The hook is called with the following parameters:
#
# $1 -- the upstream the series was forked from.
# $2 -- the branch being rebased (or empty when rebasing the current branch).
#
# This sample shows how to prevent topic branches that are already
# merged to 'next' branch from getting rebased, because allowing it
# would result in rebasing already published history.

publish=next
basebranch="$1"
if test "$#" = 2
then
	topic="refs/heads/$2"
else
	topic=`git symbolic-ref HEAD` ||
	exit 0 ;# we do not interrupt rebasing detached HEAD
fi

case "$topic" in
refs/heads/??/*)
	;;
*)
	exit 0 ;# we do not interrupt others.
	;;
esac

# Now we are dealing with a topic branch being rebased
# on top of master.  Is it OK to rebase it?

# Does the topic really exist?
git show-ref -q "$topic" || {
	echo >&2 "No such branch $topic"
	exit 1
}

# Is topic fully merged to master?
not_in_master=`git rev-list --pretty=oneline ^master "$topic"`
if test -z "$not_in_master"
then
	echo >&2 "$topic is fully merged to master; better remove it."
	exit 1 ;# we could allow it, but there is no point.
fi

# Is topic ever merged to next?  If so you should not be rebasing it.
only_next_1=`git rev-list ^master "^$topic" ${publish} | sort`
only_next_2=`git rev-list ^master           ${publish} | sort`
if test "$only_next_1" = "$only_next_2"
then
	not_in_topic=`git rev-list "^$topic" master`
	if test -z "$not_in_topic"
	then
		echo >&2 "$topic is already up-to-date with master"
		exit 1 ;# we could allow it, but there is no point.
	else
		exit 0
	fi
else
	not_in_next=`git rev-list --pretty=oneline ^${publish} "$topic"`
	/usr/bin/perl -e '
		my $topic = $ARGV[0];
		my $msg = "* $topic has commits already merged to public branch:\n";
		my (%not_in_next) = map {
			/^([0-9a-f]+) /;
			($1 => 1);
		} split(/\n/, $ARGV[1]);
		for my $elem (map {
				/^([0-9a-f]+) (.*)$/;
				[$1 => $2];
			} split(/\n/, $ARGV[2])) {
			if (!exists $not_in_next{$elem->[0]}) {
				if ($msg) {
					print STDERR $msg;
					undef $msg;
				}
				print STDERR " $elem->[1]\n";
			}
		}
	' "$topic" "$not_in_next" "$not_in_master"
	exit 1
fi

exit 0

################################################################

This sample hook safeguards topic branches that have been
published from being rewound.

The workflow assumed here is:

 * Once a topic branch forks from "master", "master" is never
   merged into it again (either directly or indirectly).

 * Once a topic branch is fully cooked and merged into "master",
   it is deleted.  If you need to build on top of it to correct
   earlier mistakes, a new topic branch is created by forking at
   the tip of the "master".  This is not strictly necessary, but
   it makes it easier to keep your history simple.

 * Whenever you need to test or publish your changes to topic
   branches, merge them into "next" branch.

The script, being an example, hardcodes the publish branch name
to be "next", but it is trivial to make it configurable via
$GIT_DIR/config mechanism.

With this workflow, you would want to know:

(1) ... if a topic branch has ever been merged to "next".  Young
    topic branches can have stupid mistakes you would rather
    clean up before publishing, and things that have not been
    merged into other branches can be easily rebased without
    affecting other people.  But once it is published, you would
    not want to rewind it.

(2) ... if a topic branch has been fully merged to "master".
    Then you can delete it.  More importantly, you should not
    build on top of it -- other people may already want to
    change things related to the topic as patches against your
    "master", so if you need further changes, it is better to
    fork the topic (perhaps with the same name) afresh from the
    tip of "master".

Let's look at this example:

		   o---o---o---o---o---o---o---o---o---o "next"
		  /       /           /           /
		 /   a---a---b A     /           /
		/   /               /           /
	       /   /   c---c---c---c B         /
	      /   /   /             \         /
	     /   /   /   b---b C     \       /
	    /   /   /   /             \     /
    ---o---o---o---o---o---o---o---o---o---o---o "master"


A, B and C are topic branches.

 * A has one fix since it was merged up to "next".

 * B has finished.  It has been fully merged up to "master" and "next",
   and is ready to be deleted.

 * C has not merged to "next" at all.

We would want to allow C to be rebased, refuse A, and encourage
B to be deleted.

To compute (1):

	git rev-list ^master ^topic next
	git rev-list ^master        next

	if these match, topic has not merged in next at all.

To compute (2):

	git rev-list master..topic

	if this is empty, it is fully merged to "master".

Added wiki_references/2017/software/MaidSafe_net/src_from_GitHub/the_repository_clones/MaidSafe-DHT/.git/hooks/prepare-commit-msg.sample version [2b6275eda3].









































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#!/bin/sh
#
# An example hook script to prepare the commit log message.
# Called by "git commit" with the name of the file that has the
# commit message, followed by the description of the commit
# message's source.  The hook's purpose is to edit the commit
# message file.  If the hook fails with a non-zero status,
# the commit is aborted.
#
# To enable this hook, rename this file to "prepare-commit-msg".

# This hook includes three examples.  The first comments out the
# "Conflicts:" part of a merge commit.
#
# The second includes the output of "git diff --name-status -r"
# into the message, just before the "git status" output.  It is
# commented because it doesn't cope with --amend or with squashed
# commits.
#
# The third example adds a Signed-off-by line to the message, that can
# still be edited.  This is rarely a good idea.

case "$2,$3" in
  merge,)
    /usr/bin/perl -i.bak -ne 's/^/# /, s/^# #/#/ if /^Conflicts/ .. /#/; print' "$1" ;;

# ,|template,)
#   /usr/bin/perl -i.bak -pe '
#      print "\n" . `git diff --cached --name-status -r`
#	 if /^#/ && $first++ == 0' "$1" ;;

  *) ;;
esac

# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p')
# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1"

Added wiki_references/2017/software/MaidSafe_net/src_from_GitHub/the_repository_clones/MaidSafe-DHT/.git/hooks/update.sample version [39355a0759].

































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
#!/bin/sh
#
# An example hook script to blocks unannotated tags from entering.
# Called by "git receive-pack" with arguments: refname sha1-old sha1-new
#
# To enable this hook, rename this file to "update".
#
# Config
# ------
# hooks.allowunannotated
#   This boolean sets whether unannotated tags will be allowed into the
#   repository.  By default they won't be.
# hooks.allowdeletetag
#   This boolean sets whether deleting tags will be allowed in the
#   repository.  By default they won't be.
# hooks.allowmodifytag
#   This boolean sets whether a tag may be modified after creation. By default
#   it won't be.
# hooks.allowdeletebranch
#   This boolean sets whether deleting branches will be allowed in the
#   repository.  By default they won't be.
# hooks.denycreatebranch
#   This boolean sets whether remotely creating branches will be denied
#   in the repository.  By default this is allowed.
#

# --- Command line
refname="$1"
oldrev="$2"
newrev="$3"

# --- Safety check
if [ -z "$GIT_DIR" ]; then
	echo "Don't run this script from the command line." >&2
	echo " (if you want, you could supply GIT_DIR then run" >&2
	echo "  $0 <ref> <oldrev> <newrev>)" >&2
	exit 1
fi

if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then
	echo "usage: $0 <ref> <oldrev> <newrev>" >&2
	exit 1
fi

# --- Config
allowunannotated=$(git config --bool hooks.allowunannotated)
allowdeletebranch=$(git config --bool hooks.allowdeletebranch)
denycreatebranch=$(git config --bool hooks.denycreatebranch)
allowdeletetag=$(git config --bool hooks.allowdeletetag)
allowmodifytag=$(git config --bool hooks.allowmodifytag)

# check for no description
projectdesc=$(sed -e '1q' "$GIT_DIR/description")
case "$projectdesc" in
"Unnamed repository"* | "")
	echo "*** Project description file hasn't been set" >&2
	exit 1
	;;
esac

# --- Check types
# if $newrev is 0000...0000, it's a commit to delete a ref.
zero="0000000000000000000000000000000000000000"
if [ "$newrev" = "$zero" ]; then
	newrev_type=delete
else
	newrev_type=$(git cat-file -t $newrev)
fi

case "$refname","$newrev_type" in
	refs/tags/*,commit)
		# un-annotated tag
		short_refname=${refname##refs/tags/}
		if [ "$allowunannotated" != "true" ]; then
			echo "*** The un-annotated tag, $short_refname, is not allowed in this repository" >&2
			echo "*** Use 'git tag [ -a | -s ]' for tags you want to propagate." >&2
			exit 1
		fi
		;;
	refs/tags/*,delete)
		# delete tag
		if [ "$allowdeletetag" != "true" ]; then
			echo "*** Deleting a tag is not allowed in this repository" >&2
			exit 1
		fi
		;;
	refs/tags/*,tag)
		# annotated tag
		if [ "$allowmodifytag" != "true" ] && git rev-parse $refname > /dev/null 2>&1
		then
			echo "*** Tag '$refname' already exists." >&2
			echo "*** Modifying a tag is not allowed in this repository." >&2
			exit 1
		fi
		;;
	refs/heads/*,commit)
		# branch
		if [ "$oldrev" = "$zero" -a "$denycreatebranch" = "true" ]; then
			echo "*** Creating a branch is not allowed in this repository" >&2
			exit 1
		fi
		;;
	refs/heads/*,delete)
		# delete branch
		if [ "$allowdeletebranch" != "true" ]; then
			echo "*** Deleting a branch is not allowed in this repository" >&2
			exit 1
		fi
		;;
	refs/remotes/*,commit)
		# tracking branch
		;;
	refs/remotes/*,delete)
		# delete tracking branch
		if [ "$allowdeletebranch" != "true" ]; then
			echo "*** Deleting a tracking branch is not allowed in this repository" >&2
			exit 1
		fi
		;;
	*)
		# Anything else (is there anything else?)
		echo "*** Update hook: unknown type of update to ref $refname of type $newrev_type" >&2
		exit 1
		;;
esac

# --- Finished
exit 0

Added wiki_references/2017/software/MaidSafe_net/src_from_GitHub/the_repository_clones/MaidSafe-DHT/.git/index version [e1ac45c7a8].

cannot compute difference between binary files

Added wiki_references/2017/software/MaidSafe_net/src_from_GitHub/the_repository_clones/MaidSafe-DHT/.git/info/exclude version [c879df015d].













>
>
>
>
>
>
1
2
3
4
5
6
# git ls-files --others --exclude-from=.git/info/exclude
# Lines that start with '#' are comments.
# For a project mostly in C, the following would be a good set of
# exclude patterns (uncomment them if you want to use them):
# *.[oa]
# *~

Added wiki_references/2017/software/MaidSafe_net/src_from_GitHub/the_repository_clones/MaidSafe-DHT/.git/logs/HEAD version [172aa4c5ef].



>
1
0000000000000000000000000000000000000000 49d939bc678a37e05f67ad5863488e59b61616da Martin Vahi <martin.vahi@softf1.com> 1490070140 +0200	clone: from https://github.com/maidsafe/MaidSafe-DHT.git

Added wiki_references/2017/software/MaidSafe_net/src_from_GitHub/the_repository_clones/MaidSafe-DHT/.git/logs/refs/heads/master version [172aa4c5ef].



>
1
0000000000000000000000000000000000000000 49d939bc678a37e05f67ad5863488e59b61616da Martin Vahi <martin.vahi@softf1.com> 1490070140 +0200	clone: from https://github.com/maidsafe/MaidSafe-DHT.git

Added wiki_references/2017/software/MaidSafe_net/src_from_GitHub/the_repository_clones/MaidSafe-DHT/.git/logs/refs/remotes/origin/HEAD version [172aa4c5ef].



>
1
0000000000000000000000000000000000000000 49d939bc678a37e05f67ad5863488e59b61616da Martin Vahi <martin.vahi@softf1.com> 1490070140 +0200	clone: from https://github.com/maidsafe/MaidSafe-DHT.git

Added wiki_references/2017/software/MaidSafe_net/src_from_GitHub/the_repository_clones/MaidSafe-DHT/.git/objects/pack/pack-cb5c30aa6a2c5ea84f13ad926aa1661eb6ac7147.idx version [10f9e9d226].

cannot compute difference between binary files

Added wiki_references/2017/software/MaidSafe_net/src_from_GitHub/the_repository_clones/MaidSafe-DHT/.git/objects/pack/pack-cb5c30aa6a2c5ea84f13ad926aa1661eb6ac7147.pack version [0e2469b830].

cannot compute difference between binary files

Added wiki_references/2017/software/MaidSafe_net/src_from_GitHub/the_repository_clones/MaidSafe-DHT/.git/packed-refs version [6500bf53e4].



















































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# pack-refs with: peeled fully-peeled 
0acc4cb830204c9d030d2edefd68a7d4319d7248 refs/remotes/origin/cppcheck
dbfb8bde2d024e9753cb9040b5107624e4a19299 refs/remotes/origin/gh-pages
49d939bc678a37e05f67ad5863488e59b61616da refs/remotes/origin/master
98bd589d4fbcaa603999d0a8868dfc2d5ad46e8b refs/remotes/origin/nat_detection
01deb2cf9ff5eae99766bb4ca5e7fafc34023d8f refs/remotes/origin/next
bb9d92802720c4b26b77d6c014dbbfedb6a9a5ec refs/remotes/origin/nodes_explorer
a606b471481d71f62110ee98a0c3862e2ff28a26 refs/remotes/origin/remove_fw_declares
759293b75b14353a942cfd62e9bd52438ef774a7 refs/remotes/origin/using_rudp
d9783bf63fcd604ad96ff29c16ab3175a6ba9915 refs/tags/lifestuff_local_v01
84195a5496d3a2fa59fae21082c8243807ac8b38 refs/tags/v0.30.00
843080e364a965b25671e4f59aa9fbd2d81ad825 refs/tags/v0.30.01
53e0220d737ab9d100dabe68c4e7c82595dc5549 refs/tags/v0.30.02
dc3e3c0a20c5cb494b00f9f4abb4a9fb78aa904c refs/tags/v0.31.00
7cf230cbf4f2d57e05290f8387902a5bb9e59b4b refs/tags/v0.31.01
036154496398d972897516c275038deaf4f1ddc0 refs/tags/v0.31.02
76305f80d457652434992d994da320c1c09c2c43 refs/tags/v0.31.03
636b6c342a504f557dc99ab81a462f0a058bfb1d refs/tags/v0.31.04
55a15464a7c7aabb72b4e15702c0df770aba275a refs/tags/v0.31.05
0dbf5084c17ec356ba73fb507427479ff2a8836d refs/tags/v0.31.06
26ce045fb14f7e3814e15a4cf1fcfccd9f4d06e9 refs/tags/v0.31.07
11251710819568020db78bcd3226207a8691d019 refs/tags/v0.32.00
7fe8674ddb663c100aa62da2393d0d7f8d46d78f refs/tags/v27
1c80b7c4d653412544bab8b6ee52146ec0a3d429 refs/tags/v28
af935e22be8b69a571b6feedabbb500fcd95e4a1 refs/tags/v29

Added wiki_references/2017/software/MaidSafe_net/src_from_GitHub/the_repository_clones/MaidSafe-DHT/.git/refs/heads/master version [e88be7dbc0].



>
1
49d939bc678a37e05f67ad5863488e59b61616da

Added wiki_references/2017/software/MaidSafe_net/src_from_GitHub/the_repository_clones/MaidSafe-DHT/.git/refs/remotes/origin/HEAD version [d9427cda09].



>
1
ref: refs/remotes/origin/master

Added wiki_references/2017/software/MaidSafe_net/src_from_GitHub/the_repository_clones/MaidSafe-DHT/.gitignore version [bee4769bf4].



















>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
*.0
*~
*.backup
*.temp
desktop.ini
.kdev4/
*.kdev4
*.pb.h
*.pb.cc

Added wiki_references/2017/software/MaidSafe_net/src_from_GitHub/the_repository_clones/MaidSafe-DHT/CMakeLists.txt version [1e9efc145d].









































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
#==============================================================================#
#                                                                              #
#  Copyright (c) 2011 MaidSafe.net limited                                     #
#  All rights reserved.                                                        #
#                                                                              #
#  Redistribution and use in source and binary forms, with or without          #
#  modification, are permitted provided that the following conditions are met: #
#                                                                              #
#      * Redistributions of source code must retain the above copyright        #
#        notice, this list of conditions and the following disclaimer.         #
#      * Redistributions in binary form must reproduce the above copyright     #
#        notice, this list of conditions and the following disclaimer in the   #
#        documentation and/or other materials provided with the distribution.  #
#      * Neither the name of the maidsafe.net limited nor the names of its     #
#        contributors may be used to endorse or promote products derived from  #
#        this software without specific prior written permission.              #
#                                                                              #
#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" #
#  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE   #
#  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE  #
#  ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE  #
#  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR         #
#  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF        #
#  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS    #
#  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN     #
#  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)     #
#  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE  #
#  POSSIBILITY OF SUCH DAMAGE.                                                 #
#                                                                              #
#==============================================================================#
#                                                                              #
#  Written by maidsafe.net team                                                #
#                                                                              #
#==============================================================================#


SET(MS_PROJECT_NAME maidsafe_dht)

CMAKE_MINIMUM_REQUIRED(VERSION 2.8.4 FATAL_ERROR)
MESSAGE("================================================================================\n")

GET_FILENAME_COMPONENT(CMAKE_BUILD_TYPE_DIR ${CMAKE_BINARY_DIR} NAME)

# Variable MSVC is not set until after "PROJECT" command below
IF(CMAKE_BUILD_TYPE_DIR MATCHES "Win_MSVC")
  SET(CMAKE_BUILD_TYPE_DIR Release)
ELSEIF(CMAKE_BUILD_TYPE_DIR MATCHES "kdev")
  SET(CMAKE_BUILD_TYPE_DIR Debug)
  SET(KDEV 1)
ENDIF()

IF(NOT ${CMAKE_C_COMPILER_WORKS})
  MESSAGE(FATAL_ERROR "No generator previously specified.\nTo see a full list of generators, run:\n\tcmake --help\n")
ENDIF()

# This "PROJECT" command resets CMAKE_BUILD_TYPE, hence it's copied from CMAKE_BUILD_TYPE_DIR which is set above.
IF((CMAKE_BUILD_TYPE_DIR MATCHES "Release") OR (DEFINED ${KDEV}))
  PROJECT(${MS_PROJECT_NAME})
ELSE()
  STRING(TOLOWER ${CMAKE_BUILD_TYPE_DIR} MS_PROJECT_NAME_APPENDIX)
  PROJECT(${MS_PROJECT_NAME}_${MS_PROJECT_NAME_APPENDIX})
ENDIF()

SET(CMAKE_BUILD_TYPE ${CMAKE_BUILD_TYPE_DIR} CACHE INTERNAL "Except for MSVC, the build type is set by running cmake from the appropriate build subdirectory e.g. for a Debug build, \"cd build/Linux/Debug && cmake ../../..\"." FORCE)


###################################################################################################
# MaidSafe Common & Transport library search                                                      #
###################################################################################################
SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${PROJECT_SOURCE_DIR}/build)
INCLUDE(maidsafe_find_common)
ADD_MAIDSAFE_LIBRARY(MaidSafe-Transport)


###################################################################################################
# Standard setup                                                                                  #
###################################################################################################
SET(PROTO_SOURCE_DIR ${PROJECT_SOURCE_DIR}/src)
FILE(GLOB PROTO_FILES_KADEMLIA RELATIVE ${PROTO_SOURCE_DIR} "${PROTO_SOURCE_DIR}/maidsafe/dht/*.proto")
FILE(GLOB PROTO_FILES_TESTS RELATIVE ${PROTO_SOURCE_DIR} "${PROTO_SOURCE_DIR}/maidsafe/dht/tests/*.proto")
SET(PROTO_FILES "${PROTO_FILES_KADEMLIA};${PROTO_FILES_TESTS}")
INCLUDE(maidsafe_standard_setup)
HANDLE_VERSIONS(${PROJECT_SOURCE_DIR}/src/maidsafe/dht/version.h)


###################################################################################################
# Set up all files as GLOBs                                                                       #
###################################################################################################
####    CODE    ####
FILE(GLOB SOURCE_FILES_DHT_DIR "${PROJECT_SOURCE_DIR}/src/maidsafe/dht/*.cc")
FILE(GLOB HEADER_FILES_DHT_DIR "${PROJECT_SOURCE_DIR}/src/maidsafe/dht/*.h")
FILE(GLOB PROTO_FILES_DHT_DIR "${PROJECT_SOURCE_DIR}/src/maidsafe/dht/*.proto")
FILE(GLOB SOURCE_PROTO_FILES_DHT_DIR "${PROJECT_SOURCE_DIR}/src/maidsafe/dht/*.pb.cc")
FILE(GLOB HEADER_PROTO_FILES_DHT_DIR "${PROJECT_SOURCE_DIR}/src/maidsafe/dht/*.pb.h")
SET(ALL_FILES_DHT_DIR ${SOURCE_FILES_DHT_DIR} ${HEADER_FILES_DHT_DIR} ${PROTO_FILES_DHT_DIR})
SET(STYLE_DHT ${ALL_FILES_DHT_DIR})
LIST(REMOVE_ITEM STYLE_DHT ${SOURCE_PROTO_FILES_DHT_DIR} ${HEADER_PROTO_FILES_DHT_DIR} ${PROTO_FILES_DHT_DIR})
LIST(REMOVE_ITEM SOURCE_FILES_DHT_DIR ${SOURCE_PROTO_FILES_DHT_DIR})
LIST(REMOVE_ITEM HEADER_FILES_DHT_DIR ${HEADER_PROTO_FILES_DHT_DIR})
SOURCE_GROUP("DHT Source Files" FILES ${SOURCE_FILES_DHT_DIR})
SOURCE_GROUP("DHT Header Files" FILES ${HEADER_FILES_DHT_DIR})
SOURCE_GROUP("DHT Proto Files" FILES ${PROTO_FILES_DHT_DIR} ${SOURCE_PROTO_FILES_DHT_DIR} ${HEADER_PROTO_FILES_DHT_DIR})

####    BENCHMARK, DEMO & TESTS    ####
FILE(GLOB SOURCE_FILES_BENCHMARK_DIR "${PROJECT_SOURCE_DIR}/src/maidsafe/dht/benchmark/*.cc")
FILE(GLOB HEADER_FILES_BENCHMARK_DIR "${PROJECT_SOURCE_DIR}/src/maidsafe/dht/benchmark/*.h")
SET(ALL_FILES_BENCHMARK_DIR ${SOURCE_FILES_BENCHMARK_DIR} ${HEADER_FILES_BENCHMARK_DIR})
SOURCE_GROUP("Benchmark Source Files" FILES ${SOURCE_FILES_BENCHMARK_DIR})
SOURCE_GROUP("Benchmark Header Files" FILES ${HEADER_FILES_BENCHMARK_DIR})

FILE(GLOB SOURCE_FILES_DEMO_DIR "${PROJECT_SOURCE_DIR}/src/maidsafe/dht/demo/*.cc")
FILE(GLOB HEADER_FILES_DEMO_DIR "${PROJECT_SOURCE_DIR}/src/maidsafe/dht/demo/*.h")
SET(ALL_FILES_DEMO_DIR ${SOURCE_FILES_DEMO_DIR} ${HEADER_FILES_DEMO_DIR})
SOURCE_GROUP("Demo Source Files" FILES ${SOURCE_FILES_DEMO_DIR})
SOURCE_GROUP("Demo Header Files" FILES ${HEADER_FILES_DEMO_DIR})

FILE(GLOB SOURCE_FILES_DHT_TESTS_DIR "${PROJECT_SOURCE_DIR}/src/maidsafe/dht/tests/*.cc")
FILE(GLOB HEADER_FILES_DHT_TESTS_DIR "${PROJECT_SOURCE_DIR}/src/maidsafe/dht/tests/*.h")
FILE(GLOB PROTO_FILES_DHT_TESTS_DIR "${PROJECT_SOURCE_DIR}/src/maidsafe/dht/tests/*.proto")
FILE(GLOB SOURCE_PROTO_FILES_DHT_TESTS_DIR "${PROJECT_SOURCE_DIR}/src/maidsafe/dht/tests/*.pb.cc")
FILE(GLOB HEADER_PROTO_FILES_DHT_TESTS_DIR "${PROJECT_SOURCE_DIR}/src/maidsafe/dht/tests/*.pb.h")
SET(ALL_FILES_DHT_TESTS_DIR ${SOURCE_FILES_DHT_TESTS_DIR} ${HEADER_FILES_DHT_TESTS_DIR} ${PROTO_FILES_DHT_TESTS_DIR})
SET(STYLE_DHT_TESTS ${ALL_FILES_DHT_TESTS_DIR})
LIST(REMOVE_ITEM STYLE_DHT_TESTS ${SOURCE_PROTO_FILES_DHT_TESTS_DIR} ${HEADER_PROTO_FILES_DHT_TESTS_DIR} ${PROTO_FILES_DHT_TESTS_DIR})
LIST(REMOVE_ITEM SOURCE_FILES_DHT_TESTS_DIR ${SOURCE_PROTO_FILES_DHT_TESTS_DIR})
LIST(REMOVE_ITEM HEADER_FILES_DHT_TESTS_DIR ${HEADER_PROTO_FILES_DHT_TESTS_DIR})
SOURCE_GROUP("DHT Tests Source Files" FILES ${SOURCE_FILES_DHT_TESTS_DIR})
SOURCE_GROUP("DHT Tests Header Files" FILES ${HEADER_FILES_DHT_TESTS_DIR})
SOURCE_GROUP("DHT Tests Proto Files" FILES ${PROTO_FILES_DHT_TESTS_DIR} ${SOURCE_PROTO_FILES_DHT_TESTS_DIR} ${HEADER_PROTO_FILES_DHT_TESTS_DIR})

FILE(GLOB SOURCE_FILES_DHT_TESTS_FUNCTIONAL_DIR "${PROJECT_SOURCE_DIR}/src/maidsafe/dht/tests/functional/*.cc")
FILE(GLOB HEADER_FILES_DHT_TESTS_FUNCTIONAL_DIR "${PROJECT_SOURCE_DIR}/src/maidsafe/dht/tests/functional/*.h")
SET(ALL_FILES_DHT_TESTS_FUNCTIONAL_DIR ${SOURCE_FILES_DHT_TESTS_FUNCTIONAL_DIR} ${HEADER_FILES_DHT_TESTS_FUNCTIONAL_DIR})
SOURCE_GROUP("Functional Tests Source Files" FILES ${SOURCE_FILES_DHT_TESTS_FUNCTIONAL_DIR})
SOURCE_GROUP("Functional Tests Header Files" FILES ${HEADER_FILES_DHT_TESTS_FUNCTIONAL_DIR})

SET(SOURCE_FILES_DHT_TESTS_FUNCTIONAL_NODE "${PROJECT_SOURCE_DIR}/src/maidsafe/dht/tests/functional/node_test.cc"
                                           "${PROJECT_SOURCE_DIR}/src/maidsafe/dht/tests/test_utils.cc"
                                           "${PROJECT_SOURCE_DIR}/src/maidsafe/dht/tests/test_main.cc")
SET(SOURCE_FILES_DHT_TESTS_FUNCTIONAL_NODE_IMPL "${PROJECT_SOURCE_DIR}/src/maidsafe/dht/tests/functional/node_impl_test.cc"
                                                "${PROJECT_SOURCE_DIR}/src/maidsafe/dht/tests/test_utils.cc"
                                                "${PROJECT_SOURCE_DIR}/src/maidsafe/dht/tests/test_main.cc")
SET(SOURCE_FILES_DHT_TESTS_FUNCTIONAL_NODE_CHURN "${PROJECT_SOURCE_DIR}/src/maidsafe/dht/tests/functional/node_churn_test.cc"
                                                 "${PROJECT_SOURCE_DIR}/src/maidsafe/dht/tests/test_utils.cc"
                                                 "${PROJECT_SOURCE_DIR}/src/maidsafe/dht/tests/test_main.cc")
SET(HEADER_FILES_DHT_TESTS_FUNCTIONALS "${PROJECT_SOURCE_DIR}/src/maidsafe/dht/tests/functional/test_node_environment.h"
                                       "${PROJECT_SOURCE_DIR}/src/maidsafe/dht/tests/test_utils.h"
                                       "${PROJECT_SOURCE_DIR}/src/maidsafe/dht/tests/local_network.h")


###################################################################################################
# Define MaidSafe libraries and executables                                                       #
###################################################################################################
MS_ADD_STATIC_LIBRARY(${MS_PROJECT_NAME} ${ALL_FILES_DHT_DIR})
MS_ADD_EXECUTABLE(TESTkademlia Tests ${ALL_FILES_DHT_TESTS_DIR})
MS_ADD_EXECUTABLE(TESTnode_functional Tests ${SOURCE_FILES_DHT_TESTS_FUNCTIONAL_NODE} ${HEADER_FILES_DHT_TESTS_FUNCTIONALS})
MS_ADD_EXECUTABLE(TESTnode_impl_functional Tests ${SOURCE_FILES_DHT_TESTS_FUNCTIONAL_NODE_IMPL} ${HEADER_FILES_DHT_TESTS_FUNCTIONALS})
MS_ADD_EXECUTABLE(TESTnode_churn Tests ${SOURCE_FILES_DHT_TESTS_FUNCTIONAL_NODE_CHURN} ${HEADER_FILES_DHT_TESTS_FUNCTIONALS})
MS_ADD_EXECUTABLE(KademliaDemo Demo ${ALL_FILES_DEMO_DIR})
MS_ADD_EXECUTABLE(Benchmark Benchmark ${ALL_FILES_BENCHMARK_DIR})

# This target allows maidsafe_dht_static to be installed without building all project targets
IF(MSVC)
  ADD_CUSTOM_TARGET(install_fast ${CMAKE_COMMAND} -DBUILD_TYPE=$<CONFIGURATION> -P ${CMAKE_BINARY_DIR}/cmake_install.cmake)
ELSE()
  ADD_CUSTOM_TARGET(install_fast ${CMAKE_COMMAND} -DBUILD_TYPE=${CMAKE_BUILD_TYPE} -P ${CMAKE_BINARY_DIR}/cmake_install.cmake)
ENDIF()
ADD_DEPENDENCIES(install_fast maidsafe_dht_static)

IF(NOT APPLE)
TARGET_LINK_LIBRARIES(maidsafe_dht_static
                        maidsafe_transport_static
                        maidsafe_common_static
                        breakpad_static
                        boost_date_time
                        boost_regex)
ELSE()
TARGET_LINK_LIBRARIES(maidsafe_dht_static
                        maidsafe_transport_static
                        maidsafe_common_static
                        boost_date_time
                        boost_regex)
ENDIF()
TARGET_LINK_LIBRARIES(TESTkademlia maidsafe_dht_static gmock_static)
TARGET_LINK_LIBRARIES(TESTnode_functional maidsafe_dht_static gtest_static)
TARGET_LINK_LIBRARIES(TESTnode_impl_functional maidsafe_dht_static gtest_static)
TARGET_LINK_LIBRARIES(TESTnode_churn maidsafe_dht_static gtest_static)
TARGET_LINK_LIBRARIES(KademliaDemo maidsafe_dht_static boost_program_options)
TARGET_LINK_LIBRARIES(Benchmark maidsafe_dht_static boost_program_options)


###################################################################################################
# Set compiler and linker flags                                                                   #
###################################################################################################
INCLUDE(maidsafe_standard_flags)

SET_TARGET_PROPERTIES(TESTnode_functional PROPERTIES COMPILE_DEFINITIONS "FUNCTIONAL_NODE_TEST")
SET_TARGET_PROPERTIES(TESTnode_impl_functional PROPERTIES COMPILE_DEFINITIONS "FUNCTIONAL_NODE_IMPL_TEST")
SET_TARGET_PROPERTIES(TESTnode_churn PROPERTIES COMPILE_DEFINITIONS "FUNCTIONAL_CHURN_TEST")

IF(MSVC)
  # Warnings switched off for protocol buffer generated files
  SET_SOURCE_FILES_PROPERTIES(${PROJECT_SOURCE_DIR}/src/maidsafe/dht/kademlia.pb.cc
                              ${PROJECT_SOURCE_DIR}/src/maidsafe/dht/rpcs.pb.cc
                              ${PROJECT_SOURCE_DIR}/src/maidsafe/dht/tests/wrapper.pb.cc
                                PROPERTIES COMPILE_FLAGS "/W0")
  SET_TARGET_PROPERTIES(maidsafe_dht_static TESTkademlia PROPERTIES COMPILE_FLAGS "/bigobj")
ELSEIF(UNIX)
  SET_TARGET_PROPERTIES(KademliaDemo PROPERTIES COMPILE_FLAGS "-g")
  FILE(GLOB PROTO_SOURCE_FILES "${PROJECT_SOURCE_DIR}/src/maidsafe/dht/*.pb.cc"
                               "${PROJECT_SOURCE_DIR}/src/maidsafe/dht/tests/*.pb.cc")
  SET_SOURCE_FILES_PROPERTIES(${PROJECT_SOURCE_DIR}/src/maidsafe/dht/service.cc
                              ${PROJECT_SOURCE_DIR}/src/maidsafe/dht/node.cc
                              ${PROJECT_SOURCE_DIR}/src/maidsafe/dht/node_impl.cc
                              ${PROJECT_SOURCE_DIR}/src/maidsafe/dht/benchmark/benchmark.cc
                              ${PROJECT_SOURCE_DIR}/src/maidsafe/dht/tests/test_main.cc
                              ${PROJECT_SOURCE_DIR}/src/maidsafe/dht/tests/mock_rpcs_test.cc
                              ${PROJECT_SOURCE_DIR}/src/maidsafe/dht/tests/mock_node_impl_test.cc
                              ${PROJECT_SOURCE_DIR}/src/maidsafe/dht/tests/rpcs_test.cc
                              ${PROJECT_SOURCE_DIR}/src/maidsafe/dht/tests/services_test.cc
                              ${PROJECT_SOURCE_DIR}/src/maidsafe/dht/tests/functional/node_churn_test
                              ${PROJECT_SOURCE_DIR}/src/maidsafe/dht/tests/functional/node_test.cc
                              ${PROJECT_SOURCE_DIR}/src/maidsafe/dht/tests/functional/node_impl_test.cc
                              PROPERTIES COMPILE_FLAGS "-Wno-effc++")
  SET_SOURCE_FILES_PROPERTIES(${PROTO_SOURCE_FILES} PROPERTIES COMPILE_FLAGS "-w")
ENDIF()


###################################################################################################
# Tests                                                                                           #
###################################################################################################
ADD_STYLE_TEST(${STYLE_DHT}
               ${ALL_FILES_BENCHMARK_DIR}
               ${ALL_FILES_DEMO_DIR}
               ${STYLE_DHT_TESTS}
               ${ALL_FILES_DHT_TESTS_FUNCTIONAL_DIR})

ADD_GTESTS(TESTkademlia)
ADD_GTESTS(TESTnode_functional)
ADD_GTESTS(TESTnode_impl_functional)
ADD_GTESTS(TESTnode_churn)

TEST_SUMMARY_OUTPUT()

# Remove most lengthy tests and style checkers from MemCheck runs.
ADD_MEMCHECK_IGNORE(STYLE_CHECK)
ADD_MEMCHECK_IGNORE(NodeTest.FUNC_Ping)
ADD_MEMCHECK_IGNORE(NodeTest.FUNC_Bootstrap)
ADD_MEMCHECK_IGNORE(NodeTest.FUNC_JoinClient)
ADD_MEMCHECK_IGNORE(NodeTest.FUNC_StoreAndFindSmallValue)
ADD_MEMCHECK_IGNORE(NodeTest.FUNC_StoreAndFindBigValue)
ADD_MEMCHECK_IGNORE(NodeTest.FUNC_StoreAndFindMultipleValues)
ADD_MEMCHECK_IGNORE(NodeTest.FUNC_MultipleNodesFindSingleValue)
ADD_MEMCHECK_IGNORE(NodeTest.FUNC_ClientFindValue)
ADD_MEMCHECK_IGNORE(NodeTest.FUNC_GetContact)
ADD_MEMCHECK_IGNORE(NodeTest.FUNC_FindNonExistingValue)
ADD_MEMCHECK_IGNORE(NodeTest.FUNC_FindDeadNode)
ADD_MEMCHECK_IGNORE(NodeTest.FUNC_JoinLeave)
ADD_MEMCHECK_IGNORE(NodeTest.FUNC_StoreWithInvalidRequest)
ADD_MEMCHECK_IGNORE(NodeTest.FUNC_Update)
ADD_MEMCHECK_IGNORE(NodeTest.FUNC_FindNodes)
ADD_MEMCHECK_IGNORE(NodeTest.FUNC_Delete)
ADD_MEMCHECK_IGNORE(NodeTest.FUNC_InvalidDeleteRequest)
ADD_MEMCHECK_IGNORE(FullOrClient/NodeImplTest.FUNC_JoinLeave/0)
ADD_MEMCHECK_IGNORE(FullOrClient/NodeImplTest.FUNC_JoinLeave/1)
ADD_MEMCHECK_IGNORE(FullOrClient/NodeImplTest.FUNC_FindNodes/0)
ADD_MEMCHECK_IGNORE(FullOrClient/NodeImplTest.FUNC_FindNodes/1)
ADD_MEMCHECK_IGNORE(FullOrClient/NodeImplTest.FUNC_Store/0)
ADD_MEMCHECK_IGNORE(FullOrClient/NodeImplTest.FUNC_Store/1)
ADD_MEMCHECK_IGNORE(FullOrClient/NodeImplTest.FUNC_FindValue/0)
ADD_MEMCHECK_IGNORE(FullOrClient/NodeImplTest.FUNC_FindValue/1)
ADD_MEMCHECK_IGNORE(FullOrClient/NodeImplTest.FUNC_Delete/0)
ADD_MEMCHECK_IGNORE(FullOrClient/NodeImplTest.FUNC_Delete/1)
ADD_MEMCHECK_IGNORE(FullOrClient/NodeImplTest.FUNC_Update/1)
ADD_MEMCHECK_IGNORE(FullOrClient/NodeImplTest.FUNC_StoreRefresh/0)
ADD_MEMCHECK_IGNORE(FullOrClient/NodeImplTest.FUNC_StoreRefresh/1)
ADD_MEMCHECK_IGNORE(FullOrClient/NodeImplTest.FUNC_DeleteRefresh/0)
ADD_MEMCHECK_IGNORE(FullOrClient/NodeImplTest.FUNC_DeleteRefresh/1)
ADD_MEMCHECK_IGNORE(FullOrClient/NodeImplTest.FUNC_GetContact/0)
ADD_MEMCHECK_IGNORE(FullOrClient/NodeImplTest.FUNC_GetContact/1)
ADD_MEMCHECK_IGNORE(NodeChurnTest.FUNC_RandomStartStopNodes)


###################################################################################################
# Install details                                                                                 #
###################################################################################################
FINAL_MESSAGE()
RENAME_OUTDATED_BUILT_EXES()

SET(MAIDSAFE_DHT_INSTALL_FILES
      ${PROJECT_SOURCE_DIR}/src/maidsafe/dht/config.h
      ${PROJECT_SOURCE_DIR}/src/maidsafe/dht/contact.h
      ${PROJECT_SOURCE_DIR}/src/maidsafe/dht/maidsafe-dht.h
      ${PROJECT_SOURCE_DIR}/src/maidsafe/dht/message_handler.h
      ${PROJECT_SOURCE_DIR}/src/maidsafe/dht/node-api.h
      ${PROJECT_SOURCE_DIR}/src/maidsafe/dht/node_container.h
      ${PROJECT_SOURCE_DIR}/src/maidsafe/dht/node_id.h
      ${PROJECT_SOURCE_DIR}/src/maidsafe/dht/return_codes.h
      ${PROJECT_SOURCE_DIR}/src/maidsafe/dht/rpcs_objects.h
      ${PROJECT_SOURCE_DIR}/src/maidsafe/dht/version.h)

SET(MAIDSAFE_DHT_TEST_INSTALL_FILES
      ${PROJECT_SOURCE_DIR}/src/maidsafe/dht/tests/local_network.h)

MS_INSTALL_LIBS(maidsafe_dht_static)
MS_INSTALL_HEADERS(dht ${MAIDSAFE_DHT_INSTALL_FILES})
MS_INSTALL_HEADERS(dht/tests ${MAIDSAFE_DHT_TEST_INSTALL_FILES})
MS_INSTALL_EXPORT()

Added wiki_references/2017/software/MaidSafe_net/src_from_GitHub/the_repository_clones/MaidSafe-DHT/CTestConfig.cmake version [faed289135].



















>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
SET(CTEST_PROJECT_NAME "maidsafe_dht")
SET(CTEST_NIGHTLY_START_TIME "00:00:00 UTC")
SET(CTEST_DROP_METHOD "http")
SET(CTEST_DROP_SITE "dash.maidsafe.net")
SET(CTEST_DROP_LOCATION "/submit.php?project=maidsafe-dht")
SET(CTEST_DROP_SITE_CDASH TRUE)
IF(CMAKE_CL_64)
  SET(BUILDNAME Win-x64-MSBuild)
ENDIF()

Added wiki_references/2017/software/MaidSafe_net/src_from_GitHub/the_repository_clones/MaidSafe-DHT/ChangeLog.txt version [57c067aa70].





























































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
v0.33.00 (WIP)
--------------


v0.32.00
--------
* Fix for demo ignoring --bootstrap parameter.
* Porting ReadContactsFromFile fix.
* OSX compatibility.
* Updated Contact serialise/parse methods to use ios::binary.
* Updated logging macro.
* Contact serialisation and other changes for rudp.
* Bugfix to RPcs test.
* Added install_fast target to maidsafe-dht.
* Various changes to match updated Common functions and to make use of C++11 features.

v0.31.07
--------
* Matching the new AlternativeStore API.
* Updated Contact serialization to encode PublicKey to Base32.
* Fix for a couple of for loop conditions.
* Updated ctest config file in sync with project name change.


v0.31.06
--------
* Changed to match updated CMake modules.
* Fixed ambiguous namespace alias.
* Added setters for RSA functors.
* KademliaDemo fixed to be able to start on given port range.
* Updated to use RSA instead of Securifier


v0.31.05 (2011-11-02)
--------------
* RPCs changed to use the credentials passed in the securifier instead of
  always using the default one.
* Fix for StoreRefreshMultipleRequests and DeleteRefreshMultipleRequests
  test failures.
* Fixes bug in HandleDeleteToSelf that occasionally caused boost assertion
  failure.
* Additional NodeImpl unit tests and fixes for RemoveDownlistedContacts,
  AssessLookupState & InsertCloseContacts.
* Using Random in place of SRandom.


v0.31.03
--------

* Bootstrap changed to accept empty bootstrap list, or a list containing only
  joining node's details.  These cause the node to create a new network.
* Most Node methods now call back with kNotJoined if node not joined.
* If node not joined, it now doesn't responds to incoming requests.
* Significant rework of iterative lookup process.
* Implemented Downlist functionality.
* Implemented StoreRefresh and DeleteRefresh functionality.
* FindValue now returns kSuccess only if the value was found.  If an alternative
  store holder was found, returns kFoundAlternativeStoreHolder.  If closest
  contacts are returned, kFailedToFindValue is returned.  These codes are >= 0.
  Any other return code will be negative and will indicate failure.
* Own contact is now considered during lookups.  This means that it can be
  returned by FindNodes, FindValue, GetContact and that Store, Delete and Update
  will operate on the node initiating the request.
* Own contact can also be returned as the "needs_cache_copy" Contact.
* FindValue and FindNodes can look for > k contacts if required.
* Created OrderedContacts typedef (set of Contacts ordered by closeness to a
  target ID).
* Added methods for constructing an OrderedContacts instance.
* Devolved some of the signature validation from DataStore to Service.
* Changed Transport MessageHandler to handle uninitialised messages.
* Changed Kademlia MessageHandler to handle uninitialised messages.
* Added error logging to NodeImpl, SenderTask, and Kad Service.
* Switched off reuse_address for TCP connections.
* Removed DataStore for client-only nodes.
* Routing Table now updates contacts' details if they change.
* Better handling of second node joining existing network of one.
* Various work on NodeContainer.
* Various test fixes.

Added wiki_references/2017/software/MaidSafe_net/src_from_GitHub/the_repository_clones/MaidSafe-DHT/MemCheck.supp version [16f965f291].



































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{
   Use of uninitialised value of size 4: CryptoPP::Rijndael_Enc_AdvancedProcessBlocks(void*, unsigned int const*)
   Memcheck:Value4
   fun:_ZN8CryptoPP34Rijndael_Enc_AdvancedProcessBlocksEPvPKj
}
{
   Conditional jump or move depends on uninitialised value(s): CryptoPP::X917RNG::GenerateIntoBufferedTransformation(CryptoPP::BufferedTransformation, std::string const, unsigned long long)
   Memcheck:Cond
   fun:_ZN8CryptoPP7X917RNG34GenerateIntoBufferedTransformationERNS_22BufferedTransformationERKSsy
   fun:_ZN8CryptoPP21RandomNumberGenerator13GenerateBlockEPhj
   fun:_ZN8CryptoPP7X917RNGC1EPNS_19BlockTransformationEPKhS4_
   fun:_ZN8CryptoPP17AutoSeededX917RNGINS_8RijndaelEE6ReseedEPKhjS4_S4_
   fun:_ZN8CryptoPP17AutoSeededX917RNGINS_8RijndaelEE6ReseedEbPKhj
   fun:_ZN8CryptoPP17AutoSeededX917RNGINS_8RijndaelEEC1Ebb
   fun:_Z41__static_initialization_and_destruction_0ii
   fun:_GLOBAL__I_crypto.cc
}

Added wiki_references/2017/software/MaidSafe_net/src_from_GitHub/the_repository_clones/MaidSafe-DHT/README.md version [30d78efdb9].























>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
This library has been deprecated and is replaced with MaidSafe-Routing, now found at https://github.com/maidsafe/MaidSafe-Routing/wiki.

This now forms part of a much larger codebase and the DHT may still be used as a stand-alone DHT. It has some dependencies which are easily met by following the build instructions for the MaidSafe super project.

We welcome developers to join us over at https://github.com/maidsafe/MaidSafe/wiki


For full build instructions, see https://github.com/maidsafe/MaidSafe-DHT/wiki/Developer-Build-Instructions
Abbreviated instructions can be found in build/<DirAppropriateToYourOS>/README

[![githalytics.com alpha](https://cruel-carlota.pagodabox.com/a99845d7aa40001cea85d61942c7358c "githalytics.com")](http://githalytics.com/maidsafe/MaidSafe-DHT)

Added wiki_references/2017/software/MaidSafe_net/src_from_GitHub/the_repository_clones/MaidSafe-DHT/build/Linux/Debug/.gitignore version [886e6d00ac].





>
>
1
2
*
!.gitignore

Added wiki_references/2017/software/MaidSafe_net/src_from_GitHub/the_repository_clones/MaidSafe-DHT/build/Linux/MinSizeRel/.gitignore version [886e6d00ac].





>
>
1
2
*
!.gitignore

Added wiki_references/2017/software/MaidSafe_net/src_from_GitHub/the_repository_clones/MaidSafe-DHT/build/Linux/README version [a7ac97a403].

























>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
Linux Build Instructions
========================

#  cd to build dir for Linux matching the build type required (build/Linux/Debug, build/Linux/Release, etc.)
#  Run cmake ../../.. -G"CodeBlocks - Unix Makefiles"
#  Run make (this will make all). Other options:

    *  Run make Experimental to configure, build, test and upload to our dashboard.
    *  Run make package to create auto rpm or deb.
    *  Run make install to install the maidsafe-dht library to /usr/lib and headers to /usr/include.

For full build instructions, see http://code.google.com/p/maidsafe-dht/wiki/DevBuild

Added wiki_references/2017/software/MaidSafe_net/src_from_GitHub/the_repository_clones/MaidSafe-DHT/build/Linux/RelWithDebInfo/.gitignore version [886e6d00ac].





>
>
1
2
*
!.gitignore

Added wiki_references/2017/software/MaidSafe_net/src_from_GitHub/the_repository_clones/MaidSafe-DHT/build/Linux/Release/.gitignore version [886e6d00ac].





>
>
1
2
*
!.gitignore

Added wiki_references/2017/software/MaidSafe_net/src_from_GitHub/the_repository_clones/MaidSafe-DHT/build/Linux/mkcodeblockslinux.sh version [d8e4d4c4be].





>
>
1
2
#!/bin/bash
cmake ../../.. -G"CodeBlocks - Unix Makefiles"

Added wiki_references/2017/software/MaidSafe_net/src_from_GitHub/the_repository_clones/MaidSafe-DHT/build/OSX/Debug/.gitignore version [886e6d00ac].





>
>
1
2
*
!.gitignore

Added wiki_references/2017/software/MaidSafe_net/src_from_GitHub/the_repository_clones/MaidSafe-DHT/build/OSX/MinSizeRel/.gitignore version [886e6d00ac].





>
>
1
2
*
!.gitignore

Added wiki_references/2017/software/MaidSafe_net/src_from_GitHub/the_repository_clones/MaidSafe-DHT/build/OSX/README version [1c34670096].

























>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
OSX Build Instructions
======================

#  cd to build dir for OSX matching the build type required (build/OSX/Debug, build/OSX/Release, etc.)
#  Run cmake ../../.. -G"CodeBlocks - Unix Makefiles"
#  Run make (this will make all). Other options:

    *  Run make Experimental to configure, build, test and upload to our dashboard.
    *  Run make package to create auto rpm or deb.
    *  Run make install to install the maidsafe-dht library to /usr/lib and headers to /usr/include.

For full build instructions, see http://code.google.com/p/maidsafe-dht/wiki/DevBuild

Added wiki_references/2017/software/MaidSafe_net/src_from_GitHub/the_repository_clones/MaidSafe-DHT/build/OSX/RelWithDebInfo/.gitignore version [886e6d00ac].





>
>
1
2
*
!.gitignore

Added wiki_references/2017/software/MaidSafe_net/src_from_GitHub/the_repository_clones/MaidSafe-DHT/build/OSX/Release/.gitignore version [886e6d00ac].





>
>
1
2
*
!.gitignore

Added wiki_references/2017/software/MaidSafe_net/src_from_GitHub/the_repository_clones/MaidSafe-DHT/build/README version [15ad81f8fb].











>
>
>
>
>
1
2
3
4
5
Do not build files from this directory - cd to Linux, OSX, Win_MinGW or Win_MSVC
depending on your OS and/or build tool and run the build from there.

For full build instructions, see http://code.google.com/p/maidsafe-dht/wiki/DevBuild
Abbreviated instructions can be found in src/build/<DirAppropriateToYourOS>/README

Added wiki_references/2017/software/MaidSafe_net/src_from_GitHub/the_repository_clones/MaidSafe-DHT/build/Win_MSVC/.gitignore version [9555852082].









>
>
>
>
1
2
3
4
*
!.gitignore
!extract_includes.bat
!README

Added wiki_references/2017/software/MaidSafe_net/src_from_GitHub/the_repository_clones/MaidSafe-DHT/build/Win_MSVC/README version [e3de9b48a2].



















































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
Windows Build Instructions - Building With Visual Studio
========================================================

These instructions relate to using Microsoft Visual Studio to build the project.  If you
want to use a MinGW environment instead, move to build/Win_MinGW and see the README there.

#  Open a Windows command terminal
#  cd to build dir for Windows with MSVC (build\Win_MSVC)
#  Run one of the following commands appropriate to your MSVC version:

    *  cmake ..\.. -G"Visual Studio 6"
    *  cmake ..\.. -G"Visual Studio 7"
    *  cmake ..\.. -G"Visual Studio 7 .NET 2003"
    *  cmake ..\.. -G"Visual Studio 8 2005"
    *  cmake ..\.. -G"Visual Studio 8 2005 Win64"
    *  cmake ..\.. -G"Visual Studio 9 2008"
    *  cmake ..\.. -G"Visual Studio 9 2008 Win64"
    *  cmake ..\.. -G"Visual Studio 10"
    *  cmake ..\.. -G"Visual Studio 10 Win64"

   This will create an MSVC solution (build\Win_MSVC\maidsafe_dht.sln) which
   will allow you to make all the targets from within the chosen MSVC IDE.

   Once the solution is built, you can run extract_includes.bat to create a
   directory "build\Win_MSVC\include" which will contain the public headers.

Added wiki_references/2017/software/MaidSafe_net/src_from_GitHub/the_repository_clones/MaidSafe-DHT/build/maidsafe_find_common.cmake version [f1f69c4b1e].

























































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
#==============================================================================#
#                                                                              #
#  Copyright (c) 2011 maidsafe.net limited                                     #
#  All rights reserved.                                                        #
#                                                                              #
#  Redistribution and use in source and binary forms, with or without          #
#  modification, are permitted provided that the following conditions are met: #
#                                                                              #
#      * Redistributions of source code must retain the above copyright        #
#        notice, this list of conditions and the following disclaimer.         #
#      * Redistributions in binary form must reproduce the above copyright     #
#        notice, this list of conditions and the following disclaimer in the   #
#        documentation and/or other materials provided with the distribution.  #
#      * Neither the name of the maidsafe.net limited nor the names of its     #
#        contributors may be used to endorse or promote products derived from  #
#        this software without specific prior written permission.              #
#                                                                              #
#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" #
#  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE   #
#  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE  #
#  ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE  #
#  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR         #
#  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF        #
#  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS    #
#  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN     #
#  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)     #
#  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE  #
#  POSSIBILITY OF SUCH DAMAGE.                                                 #
#                                                                              #
#==============================================================================#
#                                                                              #
#  Written by maidsafe.net team                                                #
#                                                                              #
#==============================================================================#
#                                                                              #
#  Module used to locate MaidSafe-Common tools, cmake modules and the          #
#    maidsafe_common libs and headers.                                         #
#                                                                              #
#  Settable variables to aid with finding MaidSafe-Common are:                 #
#    MAIDSAFE_COMMON_INSTALL_DIR                                               #
#                                                                              #
#  If found, a target named maidsafe_common_static is imported.                #
#                                                                              #
#  Variables set and cached by this module are:                                #
#    MaidSafeCommon_INCLUDE_DIR, MaidSafeCommon_MODULES_DIR,                   #
#    MaidSafeCommon_TOOLS_DIR and MAIDSAFE_COMMON_VERSION.                     #
#                                                                              #
#==============================================================================#

UNSET(MaidSafeCommon_MODULES_DIR CACHE)

IF(NOT MAIDSAFE_COMMON_INSTALL_DIR)
  IF(DEFAULT_THIRD_PARTY_ROOT)
    SET(MAIDSAFE_COMMON_INSTALL_DIR ${DEFAULT_THIRD_PARTY_ROOT})
  ELSE()
    GET_FILENAME_COMPONENT(MAIDSAFE_COMMON_INSTALL_DIR ${PROJECT_SOURCE_DIR} PATH)
    SET(MAIDSAFE_COMMON_INSTALL_DIR ${MAIDSAFE_COMMON_INSTALL_DIR}/MaidSafe-Common/installed)
  ENDIF()
ENDIF()

FIND_PATH(MaidSafeCommon_MODULES_DIR maidsafe_run_protoc.cmake
            PATHS ${MAIDSAFE_COMMON_INSTALL_DIR}
            PATH_SUFFIXES share/maidsafe/cmake_modules
            NO_SYSTEM_ENVIRONMENT_PATH
            NO_CMAKE_SYSTEM_PATH)

IF(NOT MaidSafeCommon_MODULES_DIR)
  SET(ERROR_MESSAGE "\nCould not find MaidSafe Common - ${MaidSafeCommon_MODULES_DIR}.\n")
  SET(ERROR_MESSAGE "${ERROR_MESSAGE}You can clone it at git@github.com:maidsafe/MaidSafe-Common.git\n\n")
  SET(ERROR_MESSAGE "${ERROR_MESSAGE}If MaidSafe Common is already installed, run:")
  SET(ERROR_MESSAGE "${ERROR_MESSAGE}\n${ERROR_MESSAGE_CMAKE_PATH} -DMAIDSAFE_COMMON_INSTALL_DIR=<Path to MaidSafe Common install directory>\n\n")
  MESSAGE(FATAL_ERROR "${ERROR_MESSAGE}")
ENDIF()

SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${MaidSafeCommon_MODULES_DIR})
INCLUDE(maidsafe_initialise_common)

Added wiki_references/2017/software/MaidSafe_net/src_from_GitHub/the_repository_clones/MaidSafe-DHT/images/KademliaDemo01.PNG version [5846b8027f].

cannot compute difference between binary files

Added wiki_references/2017/software/MaidSafe_net/src_from_GitHub/the_repository_clones/MaidSafe-DHT/images/KademliaDemo02.PNG version [99154eb4b3].

cannot compute difference between binary files

Added wiki_references/2017/software/MaidSafe_net/src_from_GitHub/the_repository_clones/MaidSafe-DHT/images/KademliaDemo03.PNG version [c4c9ff80c9].

cannot compute difference between binary files

Added wiki_references/2017/software/MaidSafe_net/src_from_GitHub/the_repository_clones/MaidSafe-DHT/images/KademliaDemo04.PNG version [0775589e52].

cannot compute difference between binary files

Added wiki_references/2017/software/MaidSafe_net/src_from_GitHub/the_repository_clones/MaidSafe-DHT/src/maidsafe/dht/benchmark/benchmark.cc version [2817cbd32f].

























































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
/* Copyright (c) 2010 maidsafe.net limited
All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

    * Redistributions of source code must retain the above copyright notice,
    this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright notice,
    this list of conditions and the following disclaimer in the documentation
    and/or other materials provided with the distribution.
    * Neither the name of the maidsafe.net limited nor the names of its
    contributors may be used to endorse or promote products derived from this
    software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include <signal.h>
#include <memory>
#include <iostream>  //  NOLINT
#include "boost/program_options.hpp"
#include "boost/filesystem/fstream.hpp"
#include "boost/filesystem.hpp"
#include "boost/lexical_cast.hpp"
#include "maidsafe/dht/log.h"
#include "maidsafe/dht/node-api.h"
#include "maidsafe/dht/node_impl.h"
#include "maidsafe/dht/benchmark/operations.h"

namespace po = boost::program_options;

namespace test_benchmark {
  static const uint16_t K = 16;
}  // namespace test_benchmark

class JoinCallback {
 public:
  JoinCallback() : result_arrived_(false), success_(false) {}
  void Callback(const std::string &/*result*/) {
//    maidsafe::GeneralResponse msg;
//    if (!msg.ParseFromString(result))
      success_ = false;
//    else
//      success_ = (msg.result());
    result_arrived_ = true;
  }
  bool result_arrived() const { return result_arrived_; }
  bool success() const { return success_; }
 private:
  bool result_arrived_, success_;
};

void conflicting_options(const po::variables_map& vm, const char* opt1,
    const char* opt2) {
  if (vm.count(opt1) && !vm[opt1].defaulted()
      && vm.count(opt2) && !vm[opt2].defaulted())
    throw std::logic_error(std::string("Conflicting options '")  + opt1 +
        "' and '" + opt2 + "'.");
}

// Function used to check that if 'for_what' is specified, then
// 'required_option' is specified too.
void option_dependency(const po::variables_map& vm,
    const char* for_what, const char* required_option) {
  if (vm.count(for_what) && !vm[for_what].defaulted())
    if (vm.count(required_option) == 0 || vm[required_option].defaulted())
      throw std::logic_error(std::string("Option '") + for_what
          + "' requires option '" + required_option + "'.");
}

bool kadconfig_empty(const std::string &/*path*/) {
//  maidsafe::KadConfig kadconfig;
//  try {
//    boost::filesystem::ifstream input(path.c_str(),
//                                      std::ios::in | std::ios::binary);
//    if (!kadconfig.ParseFromIstream(&input)) {;
//      return true;
//    }
//    input.close();
//    if (kadconfig.contact_size() == 0)
//      return true;
//  }
//  catch(const std::exception &) {
//    return true;
//  }
  return false;
}

bool write_to_kadconfig(const std::string & path,
    const std::string &/*node_id*/, const std::string &/*ip*/,
    const uint16_t &/*port*/, const std::string &/*local_ip*/,
    const uint16_t &/*local_port*/) {
//  maidsafe::KadConfig kadconfig;
//  try {
//    maidsafe::KadConfig::Contact *ctc = kadconfig.add_contact();
//    ctc->set_ip(ip);
//    ctc->set_node_id(node_id);
//    ctc->set_port(port);
//    ctc->set_local_ip(local_ip);
//    ctc->set_local_port(local_port);
//    boost::filesystem::fstream output(path.c_str(), std::ios::out |
//                                      std::ios::trunc | std::ios::binary);
//    if (!kadconfig.SerializeToOstream(&output)) {
//      output.close();
//      return false;
//    }
//    output.close();
//  }
//    catch(const std::exception &) {
//    return false;
//  }
  return boost::filesystem::exists(path);
}

int main(int argc, char **argv) {
  try {
    std::string logpath, kadconfigpath, bs_ip, bs_id, configfile,
        bs_local_ip, thisnodekconfigpath, idpath;
    uint16_t bs_port(0), bs_local_port(0), port(0);
    int iterations(5), max_nodes(5);
    po::options_description desc("Options");
    desc.add_options()
      ("help,h", "Print options information and exit.")
      ("logfilepath,l", po::value(&logpath), "Path of logfile")
      ("verbose,v", po::bool_switch(), "Print log to console.")
      ("kadconfigfile,k",
        po::value(&kadconfigpath)->default_value(kadconfigpath),
        "Complete pathname of kadconfig file. Default is Node<port>/."
        "kadconfig")
      ("port,p", po::value(&port)->default_value(port),
        "Local port to start node.  Default is 0, that starts in random port.")
      ("bs_ip", po::value(&bs_ip), "Bootstrap node ip.")
      ("bs_port", po::value(&bs_port), "Bootstrap node port.")
      ("bs_local_ip", po::value(&bs_local_ip), "Bootstrap node local ip.")
      ("bs_local_port", po::value(&bs_local_port), "Bootstrap node local port.")
      ("bs_id", po::value(&bs_id), "Bootstrap node id.")
      ("upnp", po::bool_switch(), "Use UPnP for Nat Traversal.")
      ("port_fw", po::bool_switch(), "Manually port forwarded local port.")
      ("id_list", po::value(&idpath),
        "List of nodes' IDs in the network, for lookup operations.")
      ("iterations,i", po::value(&iterations)->default_value(iterations),
        "Number of repetitions per Kad operation.")
      ("max_nodes", po::value(&max_nodes)->default_value(max_nodes),
        "Maximum number of nodes taken from id_list for Kad operations.");
      // TODO(Team#5#): 2010-04-19 - options: disable benchmarks, delay, sizes
    po::variables_map vm;
    po::store(po::parse_command_line(argc, argv, desc), vm);
    if (vm.count("help")) {
      DLOG(INFO) << desc << "\n";
      return 0;
    }
    option_dependency(vm, "bs_id", "bs_ip");
    option_dependency(vm, "bs_ip", "bs_id");
    option_dependency(vm, "bs_id", "bs_port");
    option_dependency(vm, "bs_port", "bs_id");
    option_dependency(vm, "bs_id", "bs_local_ip");
    option_dependency(vm, "bs_id", "bs_local_port");
    option_dependency(vm, "bs_local_ip", "bs_id");
    option_dependency(vm, "bs_local_port", "bs_id");
    option_dependency(vm, "max_nodes", "id_list");
    conflicting_options(vm, "upnp", "port_fw");
    conflicting_options(vm, "verbose", "logfilepath");

    // checking if path of kadconfigfile exists
    if (vm.count("kadconfigfile")) {
      kadconfigpath = vm["kadconfigfile"].as<std::string>();
      boost::filesystem::path kadconfig(kadconfigpath);
      if (!boost::filesystem::exists(kadconfig.parent_path())) {
        try {
          boost::filesystem::create_directories(kadconfig.parent_path());
          if (!vm.count("bs_id")) {
            printf("No bootstrapping info.\n");
            return 1;
          }
        }
        catch(const std::exception &) {
          if (!vm.count("bs_id")) {
            printf("No bootstrapping info.\n");
            return 1;
          }
        }
      } else {
        if (kadconfig_empty(kadconfigpath) && !vm.count("bs_id")) {
          printf("No bootstrapping info.\n");
          return 1;
        }
      }
    } else {
      if (!vm.count("bs_id")) {
        printf("No bootstrapping info.\n");
        return 1;
      }
    }

    // setting log
#ifndef HAVE_GLOG
    std::string FLAGS_log_dir;
#endif
    if (vm.count("logfilepath")) {
#ifdef HAVE_GLOG
      try {
        if (!boost::filesystem::exists(vm["logfilepath"].as<std::string>()))
          boost::filesystem::create_directories(
              vm["logfilepath"].as<std::string>());
        FLAGS_log_dir = vm["logfilepath"].as<std::string>();
      }
      catch(const std::exception &e) {
        printf("Error creating directory for log path: %s\n", e.what());
        printf("Logfile going to default dir (/tmp)\n");
      }
#endif
    } else {
      FLAGS_logtostderr = vm["verbose"].as<bool>();
    }
    maidsafe::InitLogging(argv[0]);

/*
    // Starting transport on port
    port = vm["port"].as<uint16_t>();
    boost::shared_ptr<transport::UdtTransport> tra(new transport::UdtTransport);
    transport::TransportCondition tc;
    tra->StartListening("", port, &tc);
    if (transport::kSuccess != tc) {
      printf("Node failed to start transport on port %d.\n", port);
      return 1;
    }
    boost::shared_ptr<rpcprotocol::ChannelManager> cm(
        new rpcprotocol::ChannelManager(tra));
    if (0 != cm->Start()) {
      printf("Node failed to start ChannelManager.\n");
      tra->StopListening(port);
      return 1;
    }
    kademlia::NodeConstructionParameters kcp;
    kcp.alpha = kademlia::kAlpha;
    kcp.beta = kademlia::kBeta;
    kcp.k = test_benchmark::K;
    kcp.port_forwarded = false;
    kcp.refresh_time = kademlia::kRefreshTime;
    kcp.use_upnp = false;
    kcp.type = kademlia::CLIENT;
    kcp.port = port;
    boost::shared_ptr<kademlia::Node> node(new kademlia::Node(cm, tra, kcp));

    // setting kadconfig file if it was not in the options
    if (kadconfigpath.empty()) {
      kadconfigpath = "NodeInfo" + boost::lexical_cast<std::string>(port);
      boost::filesystem::create_directories(kadconfigpath);
      kadconfigpath += "/.kadconfig";
    }

    // Joining the node to the network
    JoinCallback callback;
    node->Join(kadconfigpath,
               boost::bind(&JoinCallback::Callback, &callback, _1));
    while (!callback.result_arrived())
      Sleep(boost::posix_time::milliseconds(500));
    // Checking result of callback
    if (!callback.success()) {
      printf("Node failed to join the network.\n");
      tra->StopListening(port);
      cm->Stop();
      return 1;
    }

    // get node IDs from text file
    std::vector<kademlia::NodeId> nodes;
    if (vm.count("id_list")) {
      try {
        boost::filesystem::ifstream idf(vm["id_list"].as<std::string>(),
                                        std::ios::in);
        while (!idf.eof()) {
          char line[150];
          idf.getline(line, sizeof(line));
          try {
            kademlia::NodeId id(line, kademlia::NodeId::kHex);
            nodes.push_back(id);
          }
          catch(const std::exception &) {
          }
        }
        idf.close();
      }
      catch(const std::exception &) {
      }
    }

    size_t nodes_count = nodes.size();
    if (nodes_count > static_cast<size_t>(max_nodes) && max_nodes > 0)
      nodes.resize(max_nodes);

    printf("Read %d node IDs from list, running tests on %d of them.\n",
           nodes_count, nodes.size());

    benchmark::Operations ops(node);

    printf("\n[ Testing GetNodeContactDetails and Ping ]\n");
    ops.TestFindAndPing(nodes, iterations);

    if (nodes_count >= test_benchmark::K * kademlia::kMinSuccessfulPecentageStore) {
      printf("\n[ Testing StoreValue and FindValue (unsigned) ]\n");
      ops.TestStoreAndFind(nodes, iterations, false);
      printf("\n[ Testing StoreValue and FindValue (signed) ]\n");
      ops.TestStoreAndFind(nodes, iterations, true);
    } else {
      printf("\n[ Skipping tests of StoreValue and FindValue ]\n");
    }

    node->Leave();
    tra->StopListening(port);
    cm->Stop();
    printf("\nNode stopped successfully.\n\n");
    benchmark::Operations::PrintRpcTimings(cm->RpcTimings());
*/
  }
  catch(const std::exception &e) {
    printf("Error: %s\n", e.what());
    return 1;
  }
  return 0;
}

Added wiki_references/2017/software/MaidSafe_net/src_from_GitHub/the_repository_clones/MaidSafe-DHT/src/maidsafe/dht/benchmark/operations.cc version [9a47878682].





















































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
/* Copyright (c) 2010 maidsafe.net limited
All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

    * Redistributions of source code must retain the above copyright notice,
    this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright notice,
    this list of conditions and the following disclaimer in the documentation
    and/or other materials provided with the distribution.
    * Neither the name of the maidsafe.net limited nor the names of its
    contributors may be used to endorse or promote products derived from this
    software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include "maidsafe/dht/benchmark/operations.h"

#include <cassert>
#include <iomanip>
#include <iostream>  // NOLINT
#include <string>
#include <vector>

#include "boost/format.hpp"
#include "boost/filesystem.hpp"
#include "boost/filesystem/fstream.hpp"
#include "boost/thread.hpp"
#include "boost/tokenizer.hpp"
#include "boost/lexical_cast.hpp"

#include "maidsafe/dht/log.h"
#include "maidsafe/dht/node_id.h"
#include "maidsafe/dht/node-api.h"


namespace maidsafe {

namespace dht {

namespace benchmark {

Operations::Operations(std::shared_ptr<Node> node)
    : node_(node),
      public_key_validation_(),
      public_key_(),
      private_key_() {
//  cryobj_.set_symm_algorithm(crypto::AES_256);
//  cryobj_.set_hash_algorithm(crypto::SHA_512);
  asymm::Keys kp;
  asymm::GenerateKeyPair(&kp);
  public_key_ = kp.public_key;
  private_key_ = kp.private_key;
}

void Operations::TestFindAndPing(const std::vector<NodeId> &nodes,
                                 const int &iterations) {
  std::vector<Contact> contacts;
  {
    printf("Finding %d nodes...\n", nodes.size());

    Stats<uint64_t> stats;
    std::shared_ptr<CallbackData> data(new CallbackData());
    boost::mutex::scoped_lock lock(data->mutex);
    for (size_t i = 0; i < nodes.size(); ++i) {
//     uint64_t t = GetEpochMilliseconds();
//      node_->GetNodeContactDetails(
//            nodes[i],
//            boost::bind(&Operations::GetNodeContactDetailsCallback, this, _1,
//                        data),
//            false);
//      while (static_cast<size_t>(data->returned_count) <= i)
//        data->condition.wait(lock);
//      stats.Add(GetEpochMilliseconds() - t);
      Contact ctc;
//      ctc.ParseFromString(data->content);
      contacts.push_back(ctc);
    }

    printf("Done: total %.2f s, min/avg/max %.2f/%.2f/%.2f s\n",
            stats.Sum() / 1000.0,
            stats.Min() / 1000.0,
            stats.Mean() / 1000.0,
            stats.Max() / 1000.0);
  }
  if (!contacts.empty()) {
    printf("Pinging %d contacts, %d iterations...\n",
           contacts.size(), iterations);

    Stats<uint64_t> stats;
    for (size_t i = 0; i < contacts.size(); ++i) {
      Stats<uint64_t> it_stats;
      std::shared_ptr<CallbackData> data(new CallbackData());
      boost::mutex::scoped_lock lock(data->mutex);
      for (int j = 0; j < iterations; ++j) {
//        uint64_t t = GetEpochMilliseconds();
//        node_->Ping(contacts[i], boost::bind(
//            &Operations::PingCallback, this, _1, data));
        while (data->returned_count <= j)
          data->condition.wait(lock);
//        it_stats.Add(GetEpochMilliseconds() - t);
      }
      stats.Add(it_stats.Mean());
      printf(" Pinged contact %d, %02d/%02d times "
             "(total %.2f s, min/avg/max %.2f/%.2f/%.2f s)\n", i + 1,
             data->succeeded_count, data->returned_count,
             it_stats.Sum() / 1000.0,
             it_stats.Min() / 1000.0,
             it_stats.Mean() / 1000.0,
             it_stats.Max() / 1000.0);
    }

    printf("Done: min/avg/max %.2f/%.2f/%.2f s\n",
            stats.Min() / 1000.0,
            stats.Mean() / 1000.0,
            stats.Max() / 1000.0);
  } else {
    printf("No contacts for nodes found.\n");
  }
}

void Operations::TestStoreAndFind(const std::vector<NodeId> &nodes,
                                  const int &iterations, const bool &/*sign*/) {
  for (int val = 0; val < 4; ++val) {
    std::string size, value;
    switch (val) {
      case 0:
        value = RandomString(1 << 4);
        size = "16 byte";
        break;
      case 1:
        value = RandomString(1 << 10);
        size = "1 KB";
        break;
      case 2:
        value = RandomString(1 << 17);
        size = "128 KB";
        break;
      case 3:
        value = RandomString(1 << 20);
        size = "1 MB";
        break;
    }
    printf("Storing %s value on %d * k closest nodes, %d iterations...\n",
           size.c_str(), nodes.size(), iterations);


    Stats<uint64_t> store_stats;
    for (size_t i = 0; i < nodes.size(); ++i) {
      Stats<uint64_t> it_stats;
      std::shared_ptr<CallbackData> data(new CallbackData());
      boost::mutex::scoped_lock lock(data->mutex);
//      for (int j = 0; j < iterations; ++j) {
//        NodeId mod =
//            GetModId(val * iterations * nodes.size() + i * iterations + j);
//        NodeId key(nodes[i] ^ mod);
//        protobuf::SignedValue sig_val;
//        protobuf::MessageSignature sig_req;
//        if (sign) {
//          std::string req_sig, ser_sig_val;
//
//
//  Validifier signer;
//
//
//          sig_val.set_value(value);
// //          sig_val.set_value_signature(cryobj_.AsymSign(value, "",
// //              private_key_, crypto::STRING_STRING));
// //          ser_sig_val = sig_val.SerializeAsString();
// //          sig_req.set_signer_id(node_->node_id().String());
// //          sig_req.set_public_key(public_key_);
// //          sig_req.set_public_key_validation(public_key_validation_);
// //          sig_req.set_request_signature(req_sig);
//        }
//        uint64_t t = GetEpochMilliseconds();
//        if (sign) {
//          node_->StoreValue(key, sig_val, sig_req, 86400, boost::bind(
//              &Operations::StoreCallback, this, _1, data));
//        } else {
//          node_->StoreValue(key, value, 86400, boost::bind(
//              &Operations::StoreCallback, this, _1, data));
//        }
//        while (data->returned_count <= j)
//          data->condition.wait(lock);
//        it_stats.Add(GetEpochMilliseconds() - t);
//      }
//      store_stats.Add(it_stats.Mean());
//      printf(" Stored close to %d, %02d/%02d times "
//             "(total %.2f s, min/avg/max %.2f/%.2f/%.2f s)\n", i + 1,
//             data->succeeded_count, data->returned_count,
//             it_stats.Sum() / 1000.0,
//             it_stats.Min() / 1000.0,
//             it_stats.Mean() / 1000.0,
//             it_stats.Max() / 1000.0);
    }

    printf("Done: min/avg/max %.2f/%.2f/%.2f s\n",
           store_stats.Min() / 1000.0,
           store_stats.Mean() / 1000.0,
           store_stats.Max() / 1000.0);

    printf("Loading %s value from %d closest nodes, %d iterations...\n",
           size.c_str(), nodes.size(), iterations);

    Stats<uint64_t> load_stats;
    for (size_t i = 0; i < nodes.size(); ++i) {
      Stats<uint64_t> it_stats;
      std::shared_ptr<CallbackData> data(new CallbackData());
      boost::mutex::scoped_lock lock(data->mutex);
      for (int j = 0; j < iterations; ++j) {
        NodeId mod =
            GetModId(val * iterations * static_cast<int>(nodes.size() + i) *
                     iterations + j);
//        uint64_t t = GetEpochMilliseconds();
//        node_->FindValue(nodes[i] ^ mod, false, boost::bind(
//            &Operations::FindValueCallback, this, _1, data));
        while (data->returned_count <= j)
          data->condition.wait(lock);
//        it_stats.Add(GetEpochMilliseconds() - t);
      }
      load_stats.Add(it_stats.Mean());
      printf(" Loaded from %d, %02d/%02d times "
             "(total %.2f s, min/avg/max %.2f/%.2f/%.2f s)\n", i + 1,
             data->succeeded_count, data->returned_count,
             it_stats.Sum() / 1000.0,
             it_stats.Min() / 1000.0,
             it_stats.Mean() / 1000.0,
             it_stats.Max() / 1000.0);
    }

    printf("Done: min/avg/max %.2f/%.2f/%.2f s\n",
           load_stats.Min() / 1000.0,
           load_stats.Mean() / 1000.0,
           load_stats.Max() / 1000.0);
  }
}


void Operations::PingCallback(const std::string &/*result*/,
                              std::shared_ptr<CallbackData> data) {
  boost::mutex::scoped_lock lock(data->mutex);
  data->content.clear();
  ++data->returned_count;
//  PingResponse msg;
//  if (msg.ParseFromString(result) && msg.result())
//    ++data->succeeded_count;
  data->condition.notify_one();
}

void Operations::GetNodeContactDetailsCallback(const std::string &/*result*/,
                                  std::shared_ptr<CallbackData> data) {
  boost::mutex::scoped_lock lock(data->mutex);
  data->content.clear();
  ++data->returned_count;
//  FindNodeResult msg;
//  if (msg.ParseFromString(result) && msg.result()) {
//    ++data->succeeded_count;
//    data->content = msg.contact();
//  }
  data->condition.notify_one();
}

void Operations::StoreCallback(const std::string &/*result*/,
                               std::shared_ptr<CallbackData> data) {
  boost::mutex::scoped_lock lock(data->mutex);
  data->content.clear();
  ++data->returned_count;
//  StoreResponse msg;
//  if (msg.ParseFromString(result) && msg.result())
//    ++data->succeeded_count;
  data->condition.notify_one();
}

void Operations::FindValueCallback(const std::string &/*result*/,
                                   std::shared_ptr<CallbackData> data) {
  boost::mutex::scoped_lock lock(data->mutex);
  data->content.clear();
  ++data->returned_count;
//  FindResponse msg;
//  if (msg.ParseFromString(result) && msg.result() &&
//      (msg.values_size() > 0 || msg.signed_values_size() > 0))
//    ++data->succeeded_count;
  data->condition.notify_one();
}

/**
 * Calculates a Kademlia ID with smallest possible distance from 000..000,
 * with a unique value for each (positive) iteration number.
 */
NodeId Operations::GetModId(int iteration) {
  uint16_t bits = kKeySizeBits - 1;
  NodeId id;
  while (iteration > bits) {
    id = id ^ NodeId(bits);
    iteration -= (bits + 1);
    --bits;
  }
  return id ^ NodeId(static_cast<uint16_t>(iteration));
}

void Operations::PrintRpcTimings(const rpcprotocol::RpcStatsMap &rpc_timings) {
  DLOG(INFO) << boost::format("Calls  RPC Name  %40t% min/avg/max\n");
  for (rpcprotocol::RpcStatsMap::const_iterator it = rpc_timings.begin();
       it != rpc_timings.end();
       ++it) {
    DLOG(INFO) << boost::format("%1% : %2% %40t% %3% / %4% / %5% \n")
           % it->second.Size()
           % it->first.c_str()
           % it->second.Min()  // / 1000.0
           % it->second.Mean()  // / 1000.0
           % it->second.Max();  // / 1000.0;
  }
}

}  // namespace benchmark

}  // namespace dht

}  // namespace maidsafe

Added wiki_references/2017/software/MaidSafe_net/src_from_GitHub/the_repository_clones/MaidSafe-DHT/src/maidsafe/dht/benchmark/operations.h version [615bb5aac0].



























































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
/* Copyright (c) 2010 maidsafe.net limited
All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

    * Redistributions of source code must retain the above copyright notice,
    this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright notice,
    this list of conditions and the following disclaimer in the documentation
    and/or other materials provided with the distribution.
    * Neither the name of the maidsafe.net limited nor the names of its
    contributors may be used to endorse or promote products derived from this
    software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#ifndef MAIDSAFE_DHT_BENCHMARK_OPERATIONS_H_
#define MAIDSAFE_DHT_BENCHMARK_OPERATIONS_H_

#include <map>
#include <string>
#include <vector>
#include "boost/thread/condition_variable.hpp"
#include "boost/thread/locks.hpp"
#include "maidsafe/common/crypto.h"
#include "maidsafe/common/utils.h"
#include "maidsafe/dht/contact.h"

namespace maidsafe {

namespace dht {

namespace rpcprotocol {
typedef std::map<std::string, Stats<uint64_t>> RpcStatsMap;
}  // namespace rpcprotocol

class Node;
class NodeId;

namespace benchmark {

struct CallbackData {
  CallbackData() : returned_count(), succeeded_count(), content(), mutex(),
                   condition() {}
  int returned_count, succeeded_count;
  std::string content;
  boost::mutex mutex;
  boost::condition_variable condition;
};

class Operations {
 public:
  explicit Operations(std::shared_ptr<Node> node);
  void TestFindAndPing(const std::vector<NodeId> &nodes,
                       const int &iterations);
  void TestStoreAndFind(const std::vector<NodeId> &nodes,
                        const int &iterations, const bool &sign);
  static NodeId GetModId(int iteration);
  static void PrintRpcTimings(const rpcprotocol::RpcStatsMap &rpc_timings);
 private:
  void PingCallback(const std::string &result,
                    std::shared_ptr<CallbackData> data);
  void GetNodeContactDetailsCallback(const std::string &result,
                                     std::shared_ptr<CallbackData> data);
  void StoreCallback(const std::string &result,
                     std::shared_ptr<CallbackData> data);
  void FindValueCallback(const std::string &result,
                         std::shared_ptr<CallbackData> data);
  std::shared_ptr<Node> node_;
//  crypto::Crypto cryobj_;
  std::string public_key_validation_;
  asymm::PublicKey public_key_;
  asymm::PrivateKey private_key_;
};

}  // namespace benchmark

}  // namespace dht

}  // namespace maidsafe

#endif  // MAIDSAFE_DHT_BENCHMARK_OPERATIONS_H_

Added wiki_references/2017/software/MaidSafe_net/src_from_GitHub/the_repository_clones/MaidSafe-DHT/src/maidsafe/dht/config.h version [3006629cda].



























































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
/* Copyright (c) 2010 maidsafe.net limited
All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

    * Redistributions of source code must retain the above copyright notice,
    this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright notice,
    this list of conditions and the following disclaimer in the documentation
    and/or other materials provided with the distribution.
    * Neither the name of the maidsafe.net limited nor the names of its
    contributors may be used to endorse or promote products derived from this
    software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#ifndef MAIDSAFE_DHT_CONFIG_H_
#define MAIDSAFE_DHT_CONFIG_H_

#include <cstdint>
#include <functional>
#include <memory>
#include <string>
#include <utility>
#include <vector>

#include "boost/asio/ip/address.hpp"
#include "boost/date_time/posix_time/posix_time_duration.hpp"
#include "boost/signals2/signal.hpp"

#include "maidsafe/common/rsa.h"
#include "maidsafe/dht/return_codes.h"
#include "maidsafe/dht/version.h"

#if MAIDSAFE_DHT_VERSION != 3200
#  error This API is not compatible with the installed library.\
    Please update the maidsafe-dht library.
#endif


namespace maidsafe {

namespace transport {
class Transport;
struct Endpoint;
struct Info;
}  // namespace transport

namespace dht {

class Contact;
class NodeId;
class MessageHandler;

enum OnlineStatus { kOffline, kOnline, kAttemptingConnect };

struct FindValueReturns;

typedef std::pair<std::string, std::string> ValueAndSignature;

typedef std::shared_ptr<boost::signals2::signal<void(OnlineStatus)>>
        OnOnlineStatusChangePtr;

// Functor for use in Node::Join, Store, Delete and Update.  Parameter is the
// return code.
typedef std::function<void(int)> JoinFunctor, StoreFunctor, DeleteFunctor,  // NOLINT (Fraser)
                                 UpdateFunctor, PingFunctor;

// Functor for use in Node::FindValue.  Parameters in order are: return code,
// value(s) and signature(s) if found, k closest nodes if value not found,
// contact details of node holding cached value outside of kademlia's DataStore,
// and contact details of node needing a cache copy of the values.
typedef std::function<void(FindValueReturns)> FindValueFunctor;

// Functor for use in Node::FindNodes.  Parameters in order are: return code,
// k closest nodes.
typedef std::function<void(int, std::vector<Contact>)> FindNodesFunctor;

// Functor for use in Node::GetContact.  Parameters in order are: return code,
// node's contact details.
typedef std::function<void(int, Contact)> GetContactFunctor;

// Functor to be used as a predicate in waits and timed_waits.
typedef std::function<bool()> WaitFunctor;

typedef std::function<bool(const std::string&)> CheckCacheFunctor;  // NOLINT (Fraser)


typedef NodeId Key;
typedef boost::asio::ip::address IP;
typedef uint16_t Port;


typedef std::shared_ptr<MessageHandler> MessageHandlerPtr;
typedef std::shared_ptr<transport::Transport> TransportPtr;
typedef std::shared_ptr<asymm::Keys> KeyPairPtr;
typedef std::shared_ptr<asymm::PrivateKey> PrivateKeyPtr;
typedef std::shared_ptr<asymm::PublicKey> PublicKeyPtr;
typedef std::shared_ptr<transport::Info> RankInfoPtr;


// The size of DHT keys and node IDs in bytes.
const uint16_t kKeySizeBytes(64);

// The mean time between refreshes
const boost::posix_time::seconds kMeanRefreshInterval(1800);

// The ratio of k successful individual kad store RPCs to yield overall success.
const double kMinSuccessfulPecentageStore(0.75);

// The ratio of k successful individual kad delete RPCs to yield overall success
const double kMinSuccessfulPecentageDelete(0.75);

// The ratio of k successful individual kad update RPCs to yield overall success
const double kMinSuccessfulPecentageUpdate(0.75);

// The number of failed RPCs tolerated before a contact is removed from the
// routing table.
const uint16_t kFailedRpcTolerance(2);

// The minimum number of directly-connected contacts returned by
// GetBootstrapContacts.  If there are less than this, the list has all other
// known contacts appended.
const uint16_t kMinBootstrapContacts(8);

}  // namespace dht

}  // namespace maidsafe

#endif  // MAIDSAFE_DHT_CONFIG_H_

Added wiki_references/2017/software/MaidSafe_net/src_from_GitHub/the_repository_clones/MaidSafe-DHT/src/maidsafe/dht/contact.cc version [5ee629cdfc].











































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
/* Copyright (c) 2009 maidsafe.net limited
All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

    * Redistributions of source code must retain the above copyright notice,
    this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright notice,
    this list of conditions and the following disclaimer in the documentation
    and/or other materials provided with the distribution.
    * Neither the name of the maidsafe.net limited nor the names of its
    contributors may be used to endorse or promote products derived from this
    software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include "maidsafe/dht/contact.h"

#include <string>
#ifdef __MSVC__
#  pragma warning(push)
#  pragma warning(disable: 4127 4244 4267)
#endif
#include "maidsafe/dht/kademlia.pb.h"
#ifdef __MSVC__
#  pragma warning(pop)
#endif
#include "maidsafe/dht/log.h"
#include "maidsafe/dht/utils.h"

namespace maidsafe {

namespace dht {

Contact::Contact()
    : node_id_(),
      public_key_id_(),
      public_key_(),
      other_info_(),
      transport_details_() {}

Contact::Contact(const Contact &other)
    : node_id_(other.node_id_),
      public_key_id_(other.public_key_id_),
      public_key_(other.public_key_),
      other_info_(other.other_info_),
      transport_details_(other.transport_details_) {}

Contact::Contact(const NodeId &node_id,
                 const transport::Endpoint &endpoint,
                 const std::vector<transport::Endpoint> &local_endpoints,
                 const transport::Endpoint &rendezvous_endpoint,
                 bool tcp443,
                 bool tcp80,
                 const asymm::Identity &public_key_id,
                 const asymm::PublicKey &public_key,
                 const std::string &other_info)
    : node_id_(node_id),
      public_key_id_(public_key_id),
      public_key_(public_key),
      other_info_(other_info),
      transport_details_(transport::Contact(endpoint, local_endpoints,
                                            rendezvous_endpoint, tcp443,
                                            tcp80)) {
  Init();
}

void Contact::Init() {
  if (!node_id_.IsValid() || !transport_details_.Init())
    return Clear();
}

void Contact::Clear() {
  transport_details_.Clear();
  node_id_ = NodeId();
}

Contact::~Contact() {}

NodeId Contact::node_id() const {
  return node_id_;
}

asymm::Identity Contact::public_key_id() const {
    return public_key_id_;
}

asymm::PublicKey Contact::public_key() const {
  return public_key_;
}

std::string Contact::other_info() const {
  return other_info_;
}

transport::Endpoint Contact::endpoint() const {
  return transport_details_.endpoint();
}

std::vector<transport::Endpoint> Contact::local_endpoints() const {
  return transport_details_.local_endpoints();
}

transport::Endpoint Contact::rendezvous_endpoint() const {
  return transport_details_.rendezvous_endpoint();
}

transport::Endpoint Contact::tcp443endpoint() const {
  return transport_details_.tcp443endpoint();
}

transport::Endpoint Contact::tcp80endpoint() const {
  return transport_details_.tcp80endpoint();
}

bool Contact::SetPreferredEndpoint(const transport::IP &ip) {
  return transport_details_.SetPreferredEndpoint(ip);
}

bool Contact::MoveLocalEndpointToFirst(const transport::IP &ip) {
  return transport_details_.MoveLocalEndpointToFirst(ip);
}

bool Contact::IpMatchesEndpoint(const transport::IP &ip,
                                const transport::Endpoint &endpoint) {
  return transport_details_.IpMatchesEndpoint(ip, endpoint);
}

transport::Endpoint Contact::PreferredEndpoint() const {
  return transport_details_.PreferredEndpoint();
}

bool Contact::IsDirectlyConnected() const {
  return transport_details_.IsDirectlyConnected();
}

int Contact::Serialise(std::string * serialised) const {
  protobuf::Contact pb_contact;
  boost::system::error_code ec;

  protobuf::Endpoint *mutable_endpoint = pb_contact.mutable_endpoint();
  mutable_endpoint->set_ip(endpoint().ip.to_string(ec));
  mutable_endpoint->set_port(endpoint().port);

  if (IsValid(rendezvous_endpoint())) {
    mutable_endpoint = pb_contact.mutable_rendezvous();
    mutable_endpoint->set_ip(rendezvous_endpoint().ip.to_string(ec));
    mutable_endpoint->set_port(rendezvous_endpoint().port);
  }

  std::vector<transport::Endpoint> local_ep_vector(local_endpoints());
  for (auto it = local_ep_vector.begin(); it != local_ep_vector.end(); ++it) {
    pb_contact.add_local_ips((*it).ip.to_string(ec));
    pb_contact.set_local_port((*it).port);
  }
  if (IsValid(tcp443endpoint()))
    pb_contact.set_tcp443(true);
  if (IsValid(tcp80endpoint()))
    pb_contact.set_tcp80(true);
  // TODO(Prakash): FIXME
  if ((PreferredEndpoint().ip == rendezvous_endpoint().ip) ||
      (PreferredEndpoint().ip == endpoint().ip))
    pb_contact.set_prefer_local(false);
  else
    pb_contact.set_prefer_local(true);

  pb_contact.set_node_id(node_id().String());
  pb_contact.set_public_key_id(public_key_id());
  std::string encode_pub_key;
  asymm::EncodePublicKey(public_key(), &encode_pub_key);
  pb_contact.set_public_key(encode_pub_key);
  pb_contact.set_other_info(other_info());

  if (!pb_contact.IsInitialized())
    return kSerialisation;

  if (!pb_contact.SerializeToString(serialised)) {
    return kSerialisation;
  }
  return kSuccess;
}

int Contact::Parse(const std::string & serialised) {
  protobuf::Contact pb_contact;
  if (!pb_contact.ParseFromString(serialised)) {
    Clear();
    return kParse;
  }
  if (transport_details_.Parse(serialised) != kSuccess) {
    Clear();
    return kParse;
  }
  node_id_ = NodeId(pb_contact.node_id());

  public_key_id_ =
      pb_contact.has_public_key_id() ? pb_contact.public_key_id() : "";

  asymm::PublicKey public_key;
  if (pb_contact.has_public_key())
    asymm::DecodePublicKey(pb_contact.public_key(), &public_key);
  public_key_ = public_key;

  other_info_ =
      pb_contact.has_other_info() ? pb_contact.other_info() : "";

  return kSuccess;
}

Contact& Contact::operator=(const Contact &other) {
  if (this != &other) {
    node_id_ = other.node_id_;
    public_key_id_ = other.public_key_id_;
    public_key_ = other.public_key_;
    other_info_ = other.other_info_;
    transport_details_ = other.transport_details_;
  }
  return *this;
}

bool Contact::operator==(const Contact &other) const {
  if (node_id_ == other.node_id_)
    return (node_id_.String() != kZeroId) ||
           (endpoint().ip == other.endpoint().ip);
  else
    return false;
}

bool Contact::operator!=(const Contact &other) const {
  return !(*this == other);
}

bool Contact::operator<(const Contact &other) const {
  return node_id_ < other.node_id_;
}

bool Contact::operator>(const Contact &other) const {
  return node_id_ > other.node_id_;
}

bool Contact::operator<=(const Contact &other) const {
  return (node_id_ < other.node_id_ || (*this == other));
}

bool Contact::operator>=(const Contact &other) const {
  return (node_id_ > other.node_id_ || (*this == other));
}

std::string DebugId(const Contact &contact) {
  return DebugId(contact.node_id());
}

bool CloserToTarget(const NodeId &node_id,
                    const Contact &contact,
                    const NodeId &target) {
  return NodeId::CloserToTarget(node_id, contact.node_id(), target);
}

bool CloserToTarget(const Contact &contact1,
                    const Contact &contact2,
                    const NodeId &target) {
  return NodeId::CloserToTarget(contact1.node_id(), contact2.node_id(), target);
}

bool NodeWithinClosest(const NodeId &node_id,
                       const std::vector<Contact> &closest_contacts,
                       const NodeId &target) {
  return std::find_if(closest_contacts.rbegin(), closest_contacts.rend(),
      std::bind(static_cast<bool(*)(const NodeId&,  // NOLINT
                                    const Contact&,
                                    const NodeId&)>(&CloserToTarget),
                node_id, args::_1, target)) != closest_contacts.rend();
}

bool RemoveContact(const NodeId &node_id, std::vector<Contact> *contacts) {
  if (!contacts)
    return false;
  size_t size_before(contacts->size());
  contacts->erase(std::remove_if(contacts->begin(), contacts->end(),
                                 std::bind(&HasId, args::_1, node_id)),
                  contacts->end());
  return contacts->size() != size_before;
}

bool WriteContactsToFile(const fs::path &filename,
                         std::vector<Contact> *contacts) {
  if (contacts == nullptr)
    return false;
  protobuf::BootstrapContacts bootstrap_contacts;
  for (size_t i = 0; i < contacts->size(); i++) {
    protobuf::Contact * pb_contact = bootstrap_contacts.add_contact();
    *pb_contact = ToProtobuf(contacts->at(i));
  }
  {
    // Write the new bootstrap contacts back to disk.
    std::ofstream ofs(filename.c_str(), std::ios::binary | std::ios::trunc);
    if (!bootstrap_contacts.SerializeToOstream(&ofs)) {
      DLOG(WARNING) << "Failed to write bootstrap contacts.";
      return false;
    }
  }
  return true;
}

bool ReadContactsFromFile(const fs::path &filename,
                          std::vector<Contact> *contacts) {
  if (contacts == nullptr)
    return false;
  protobuf::BootstrapContacts bootstrap_contacts;
  {
    // Read the existing bootstrap contacts.
    std::ifstream ifs(filename.c_str(), std::ios::binary);
    if (!ifs.is_open()) {
      DLOG(WARNING) << "Failed to open file : " <<  filename.string();
      return false;
    }
    if (!bootstrap_contacts.ParseFromIstream(&ifs)) {
      DLOG(WARNING) << "Failed to parse bootstrap contacts.";
      return false;
    }
  }
  for (int i = 0; i < bootstrap_contacts.contact_size(); i++) {
    Contact contact = FromProtobuf(bootstrap_contacts.contact(i));
    contacts->push_back(contact);
  }
  return true;
}

}  // namespace dht

}  // namespace maidsafe

Added wiki_references/2017/software/MaidSafe_net/src_from_GitHub/the_repository_clones/MaidSafe-DHT/src/maidsafe/dht/contact.h version [605f06b62f].



























































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
/* Copyright (c) 2009 maidsafe.net limited
All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

    * Redistributions of source code must retain the above copyright notice,
    this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright notice,
    this list of conditions and the following disclaimer in the documentation
    and/or other materials provided with the distribution.
    * Neither the name of the maidsafe.net limited nor the names of its
    contributors may be used to endorse or promote products derived from this
    software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#ifndef MAIDSAFE_DHT_CONTACT_H_
#define MAIDSAFE_DHT_CONTACT_H_

#include <functional>
#include <memory>
#include <set>
#include <string>
#include <vector>

#include "boost/serialization/nvp.hpp"
#include "boost/serialization/vector.hpp"

#include "maidsafe/common/rsa.h"
#include "maidsafe/common/utils.h"

#include "maidsafe/transport/contact.h"
#include "maidsafe/transport/transport.h"

#include "maidsafe/dht/node_id.h"
#include "maidsafe/dht/version.h"

#if MAIDSAFE_DHT_VERSION != 3200
#  error This API is not compatible with the installed library.\
    Please update the maidsafe-dht library.
#endif

namespace args = std::placeholders;


namespace maidsafe {

namespace dht {

/** Object containing a Node's Kademlia ID and details of its endpoint(s).
 *  @class Contact */
class Contact {  // : public transport::Contact {
 public:
  /** Default constructor. */
  Contact();

  /** Copy constructor. */
  Contact(const Contact &other);

  /** Constructor.  To create a valid Contact, in all cases the node ID and
   *  endpoint must be valid, and there must be at least one valid local
   *  endpoint.  Furthermore, for a direct-connected node, there must be no
   *  rendezvous endpoint, but either of tcp443 or tcp80 may be true.  For a
   *  non-direct-connected node, both of tcp443 and tcp80 must be false, but it
   *  may have a rendezvous endpoint set.  A contact is deemed to be direct-
   *  connected if the endpoint equals the first local endpoint.
   *  @param[in] node_id The contact's Kademlia ID.
   *  @param[in] endpoint The contact's external endpoint.
   *  @param[in] local_endpoints The contact's local endpoints.  They must all
   *             have the same port, or local_endpoints_ will be set empty.
   *  @param[in] tcp443 Whether the contact is listening on TCP port 443 or not.
   *  @param[in] tcp443 Whether the contact is listening on TCP port 80 or not.
   *  @param[in] public_key_id ID of the public key which should be used to
   *             encrypt messages for this contact.
   *  @param[in] public_key Public key which should be used to encrypt messages
   *             for this contact.
   *  @param[in] other_info Any extra information to be held. */
  Contact(const NodeId &node_id,
          const transport::Endpoint &endpoint,
          const std::vector<transport::Endpoint> &local_endpoints,
          const transport::Endpoint &rendezvous_endpoint,
          bool tcp443,
          bool tcp80,
          const asymm::Identity &public_key_id,
          const asymm::PublicKey &public_key,
          const std::string &other_info);

  /** Destructor. */
  ~Contact();

  /** Getter.
   *  @return The contact's Kademlia ID. */
  NodeId node_id() const;

  /** Getter.
   *  @return ID of the public key which should be used to encrypt messages for
   *          this contact. */
  asymm::Identity public_key_id() const;

  /** Getter.
   *  @return Public key which should be used to encrypt messages for this
   *          contact. */
  asymm::PublicKey public_key() const;

  /** Getter.
   *  @return Any extra information held for this contact. */
  std::string other_info() const;

  /** Getter.
   *  @return The contact's external endpoint. */
  transport::Endpoint endpoint() const;

  /** Getter.
   *  @return The contact's local endpoints. */
  std::vector<transport::Endpoint> local_endpoints() const;

  /** Getter.
   *  @return The contact's rendezous endpoint. */
  transport::Endpoint rendezvous_endpoint() const;

  /** Getter.
   *  @return The contact's external endpoint which is on TCP port 443. */
  transport::Endpoint tcp443endpoint() const;

  /** Getter.
   *  @return The contact's external endpoint which is on TCP port 80. */
  transport::Endpoint tcp80endpoint() const;

  /** Setter to mark which of the contact's endpoints should be preferred.
   *  @param ip IP of preferred endpoint.
   *  @return Success of operation. */
  bool SetPreferredEndpoint(const transport::IP &ip);

  /** Getter.
   *  @return The contact's preferred endpoint. */
  transport::Endpoint PreferredEndpoint() const;

  /** Indicate whether the contact is directly-connected or not.
   *  @return True if directly-connected, else false. */
  bool IsDirectlyConnected() const;

  int Serialise(std::string *serialised) const;

  int Parse(const std::string &serialised);

  /** Assignment operator. */
  Contact& operator=(const Contact &other);

  // @{
  /** Equality and inequality operators.
   *  Equality is based on node ID.  However if both node IDs are kZeroId,
   *  equality is then based on endpoint IPs.  Note that this means that
   *  equality is not the same as equivalence for Contacts, where equivalence is
   *  defined as neither of two Contacts comparing < than the other, since
   *  operator< only considers node IDs. */
  bool operator==(const Contact &other) const;
  bool operator!=(const Contact &other) const;
  // @}

  // @{
  /** Comparison operators.
   *  Comparisons are based on node ID (lexicographical comparison) */
  bool operator<(const Contact &other) const;
  bool operator>(const Contact &other) const;
  bool operator<=(const Contact &other) const;
  bool operator>=(const Contact &other) const;
  // @}

 private:
  void Init();
  void Clear();
  bool MoveLocalEndpointToFirst(const transport::IP &ip);
  bool IpMatchesEndpoint(const transport::IP &ip,
                         const transport::Endpoint &endpoint);
  NodeId node_id_;
  asymm::Identity public_key_id_;
  asymm::PublicKey public_key_;
  std::string other_info_;
  transport::Contact transport_details_;
};


/** Returns an abbreviated hex representation of contact's NodeId */
std::string DebugId(const Contact &contact);

/** Returns true if node_id is closer to target than contact. */
bool CloserToTarget(const NodeId &node_id,
                    const Contact &contact,
                    const NodeId &target);

/** Returns true if contact1 is closer to target than contact2. */
bool CloserToTarget(const Contact &contact1,
                    const Contact &contact2,
                    const NodeId &target);

/** Returns true if node_id is closer to target than any of closest_contacts. */
bool NodeWithinClosest(const NodeId &node_id,
                       const std::vector<Contact> &closest_contacts,
                       const NodeId &target);

/** Erases all contacts from vector which have the given node_id and returns
 *  true if any were erased. */
bool RemoveContact(const NodeId &node_id, std::vector<Contact> *contacts);

/** Can be used to hold a set of Contacts ordered by closeness to a target. */
typedef std::set<Contact, std::function<bool(const Contact&,  // NOLINT (Fraser)
                                             const Contact&)>> OrderedContacts;

/** Creates an new empty set of Contacts ordered by closeness to target. */
inline OrderedContacts CreateOrderedContacts(const NodeId &target) {
  return OrderedContacts(
      std::bind(static_cast<bool(*)(const Contact&,           // NOLINT (Fraser)
                                    const Contact&,
                                    const NodeId&)>(&CloserToTarget),
                args::_1, args::_2, target));
}

/** Creates an new set of Contacts ordered by closeness to target, initialised
 *  with a copy of elements between first (inclusive) and last (exclusive). */
template <typename InputIterator>
OrderedContacts CreateOrderedContacts(InputIterator first,
                                      InputIterator last,
                                      const NodeId &target) {
  return OrderedContacts(first, last,
      std::bind(static_cast<bool(*)(const Contact&,           // NOLINT (Fraser)
                                    const Contact&,
                                    const NodeId&)>(&CloserToTarget),
                args::_1, args::_2, target));
}


bool WriteContactsToFile(const fs::path &filename,
                         std::vector<Contact> *contacts);

bool ReadContactsFromFile(const fs::path &filename,
                          std::vector<Contact> *contacts);

}  // namespace dht

}  // namespace maidsafe

#endif  // MAIDSAFE_DHT_CONTACT_H_

Added wiki_references/2017/software/MaidSafe_net/src_from_GitHub/the_repository_clones/MaidSafe-DHT/src/maidsafe/dht/data_store.cc version [d573a94d39].













































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
/* Copyright (c) 2009 maidsafe.net limited
All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

    * Redistributions of source code must retain the above copyright notice,
    this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright notice,
    this list of conditions and the following disclaimer in the documentation
    and/or other materials provided with the distribution.
    * Neither the name of the maidsafe.net limited nor the names of its
    contributors may be used to endorse or promote products derived from this
    software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include "maidsafe/dht/data_store.h"

#include <algorithm>

#include "maidsafe/common/crypto.h"
#include "maidsafe/common/utils.h"

#include "maidsafe/dht/log.h"
#include "maidsafe/dht/return_codes.h"

namespace args = std::placeholders;
namespace bptime = boost::posix_time;

namespace maidsafe {

namespace dht {

KeyValueTuple::KeyValueTuple(const KeyValueSignature &key_value_signature,
                             const bptime::ptime &expire_time,
                             const bptime::ptime &refresh_time,
                             const RequestAndSignature &request_and_signature,
                             bool deleted)
    : key_value_signature(key_value_signature),
      expire_time(expire_time),
      refresh_time(refresh_time),
      confirm_time(bptime::microsec_clock::universal_time() +
                   kPendingConfirmDuration),
      request_and_signature(request_and_signature),
      deleted(deleted) {}

const std::string &KeyValueTuple::key() const {
  return key_value_signature.key;
}

const std::string &KeyValueTuple::value() const {
  return key_value_signature.value;
}

void KeyValueTuple::set_refresh_time(const bptime::ptime &new_refresh_time) {
  refresh_time = new_refresh_time;
}

void KeyValueTuple::UpdateStatus(
    const bptime::ptime &new_expire_time,
    const bptime::ptime &new_refresh_time,
    const bptime::ptime &new_confirm_time,
    const RequestAndSignature &new_request_and_signature,
    bool new_deleted) {
  expire_time = new_expire_time;
  refresh_time = new_refresh_time;
  confirm_time = new_confirm_time;
  request_and_signature = new_request_and_signature;
  deleted = new_deleted;
}


DataStore::DataStore(const bptime::seconds &mean_refresh_interval)
    : key_value_index_(new KeyValueIndex),
      kRefreshInterval_(mean_refresh_interval.total_seconds() +
                        (RandomInt32() % 120)),
      shared_mutex_(),
      debug_id_("Uninitialised Debug ID") {}

bool DataStore::HasKey(const std::string &key) const {
  if (key.empty())
    return false;
  SharedLock shared_lock(shared_mutex_);
  auto itr(key_value_index_->get<TagKey>().find(key));
  DLOG(INFO) << debug_id_ << ": HasKey " << EncodeToHex(key).substr(0, 10)
             << ": " << std::boolalpha
             << (itr != key_value_index_->get<TagKey>().end());
  return (itr != key_value_index_->get<TagKey>().end());
}

int DataStore::StoreValue(
    const KeyValueSignature &key_value_signature,
    const bptime::time_duration &ttl,
    const RequestAndSignature &store_request_and_signature,
    bool is_refresh) {
  // Assumes that check on signature of request and signature of value using
  // the public key has already been done.  Also assumes that if the key
  // pre-exists, a check has been made to ensure that the same private key was
  // used to sign all pre-existing values under that key.
  if (key_value_signature.key.empty()) {
    DLOG(WARNING) << debug_id_ << ": Key empty.";
    return kEmptyKey;
  }
  if (ttl == bptime::seconds(0)) {
    DLOG(WARNING) << debug_id_ << ": Zero TTL.";
    return kZeroTTL;
  }

  bptime::ptime now(bptime::microsec_clock::universal_time());
  KeyValueTuple tuple(key_value_signature, now + ttl, now + kRefreshInterval_,
                      store_request_and_signature, false);

  // Try to insert key,value
  UniqueLock unique_lock(shared_mutex_);
  KeyValueIndex::index<TagKeyValue>::type& index_by_key_value =
      key_value_index_->get<TagKeyValue>();
  auto insertion_result = index_by_key_value.insert(tuple);

  // If the insertion succeeded, we're done.  If not, the key,value pre-existed.
  if (insertion_result.second) {
    DLOG(INFO) << debug_id_ << ": Stored key "
               << EncodeToHex(key_value_signature.key).substr(0, 10);
    return kSuccess;
  }

  // Allow original signer to modify it.
  if (!is_refresh) {
    if (index_by_key_value.modify(insertion_result.first,
        std::bind(&KeyValueTuple::UpdateStatus, args::_1, now + ttl,
                  now + kRefreshInterval_, now + kPendingConfirmDuration,
                  store_request_and_signature, false))) {
      DLOG(INFO) << debug_id_ << ": Successfully modified value for key "
                 << EncodeToHex(key_value_signature.key).substr(0, 10);
      return kSuccess;
    } else {
      DLOG(WARNING) << debug_id_ << ": Failed to modify value for key "
                    << EncodeToHex(key_value_signature.key).substr(0, 10);
      return kFailedToModifyKeyValue;
    }
  }

  // For refreshing, only the refresh time can be reset, and only for
  // non-deleted values.
  if ((*insertion_result.first).deleted) {
    DLOG(WARNING) << debug_id_ << ": Failed to refresh key "
                  << EncodeToHex(key_value_signature.key).substr(0, 10)
                  << " - marked for deletion.";
    return kMarkedForDeletion;
  }
  if (index_by_key_value.modify(insertion_result.first,
      std::bind(&KeyValueTuple::set_refresh_time, args::_1,
                now + kRefreshInterval_))) {
    DLOG(INFO) << debug_id_ << ": Successfully refreshed key "
               << EncodeToHex(key_value_signature.key).substr(0, 10);
    return kSuccess;
  } else {
    DLOG(WARNING) << debug_id_ << ": Failed to refresh key "
                  << EncodeToHex(key_value_signature.key).substr(0, 10)
                  << " - modify failed.";
    return kFailedToModifyKeyValue;
  }
}

bool DataStore::DeleteValue(
    const KeyValueSignature &key_value_signature,
    const RequestAndSignature &delete_request_and_signature,
    bool is_refresh) {
  KeyValueIndex::index<TagKeyValue>::type& index_by_key_value =
      key_value_index_->get<TagKeyValue>();
  UpgradeLock upgrade_lock(shared_mutex_);

  // If the key and value doesn't exist, return true unless is_refresh is true,
  // in which case, add the data and mark it as deleted.
  auto it = index_by_key_value.find(boost::make_tuple(key_value_signature.key,
                                    key_value_signature.value));
  bptime::ptime now(bptime::microsec_clock::universal_time());
  if (it == index_by_key_value.end()) {
    if (is_refresh) {
      // Assumes that check on signature of request and signature of value using
      // the public key has already been done.  Also assumes that if the key
      // pre-exists, a check has been made to ensure that the same private key
      // was used to sign all pre-existing values under that key.
      if (key_value_signature.key.empty()) {
        DLOG(WARNING) << debug_id_ << ": Key empty.";
        return false;
      }
      KeyValueTuple tuple(key_value_signature, now, now + kRefreshInterval_,
                          delete_request_and_signature, true);

      // Try to insert key,value
      UpgradeToUniqueLock unique_lock(upgrade_lock);
      auto insertion_result = index_by_key_value.insert(tuple);
#ifdef DEBUG
      if (!insertion_result.second) {
        DLOG(WARNING) << debug_id_ << ": Failed to insert deleted key "
                      << EncodeToHex(key_value_signature.key).substr(0, 10);
      }
#endif
      return insertion_result.second;
    } else {
      return true;
    }
  }

  // If the value is already marked as deleted, allow refresh to reset the
  // refresh time.
  if (is_refresh && (*it).deleted) {
    UpgradeToUniqueLock unique_lock(upgrade_lock);
    return index_by_key_value.modify(it,
        std::bind(&KeyValueTuple::set_refresh_time, args::_1,
                  now + kRefreshInterval_));
  }

  // Allow original signer to modify it or if value isn't marked as deleted, but
  // confirm time has expired, also allow refreshes to modify it.
  if (!is_refresh || ((*it).confirm_time < now)) {
    UpgradeToUniqueLock unique_lock(upgrade_lock);
    return index_by_key_value.modify(it,
        std::bind(&KeyValueTuple::UpdateStatus, args::_1, (*it).expire_time,
                  now + kRefreshInterval_, now + kPendingConfirmDuration,
                  delete_request_and_signature, true));
  } else {
    return false;
  }
}

bool DataStore::GetValues(
    const std::string &key,
    std::vector<ValueAndSignature> *values_and_signatures) const {
  if (!values_and_signatures)
    return false;
  values_and_signatures->clear();

  KeyValueIndex::index<TagKey>::type& index_by_key =
      key_value_index_->get<TagKey>();
  SharedLock shared_lock(shared_mutex_);
  auto itr_pair = index_by_key.equal_range(key);
  if (itr_pair.first == itr_pair.second)
    return false;

  bptime::ptime now = bptime::microsec_clock::universal_time();
  while (itr_pair.first != itr_pair.second) {
    if (((*itr_pair.first).expire_time > now) && !(*itr_pair.first).deleted)
      values_and_signatures->push_back(std::make_pair(
          (*itr_pair.first).key_value_signature.value,
          (*itr_pair.first).key_value_signature.signature));
    ++itr_pair.first;
  }
  DLOG(INFO) << debug_id_ << ": Found key " << EncodeToHex(key).substr(0, 10)
             << " with " << values_and_signatures->size() << " values.";
  return (!values_and_signatures->empty());
}

void DataStore::Refresh(std::vector<KeyValueTuple> *key_value_tuples) {
  KeyValueIndex::index<TagExpireTime>::type& index_by_expire_time =
      key_value_index_->get<TagExpireTime>();
  KeyValueIndex::index<TagRefreshTime>::type& index_by_refresh_time =
      key_value_index_->get<TagRefreshTime>();
  KeyValueIndex::index<TagConfirmTime>::type& index_by_confirm_time =
      key_value_index_->get<TagConfirmTime>();

  // Remove expired values.
  UniqueLock unique_lock(shared_mutex_);
  bptime::ptime now(bptime::microsec_clock::universal_time());
  auto it = index_by_confirm_time.begin();
  auto it_confirm_upper_bound = index_by_confirm_time.upper_bound(now);
  while (it != it_confirm_upper_bound)
    (*it).deleted ? index_by_confirm_time.erase(it++) : ++it;

  // Mark expired values as deleted.
  auto it_expire = index_by_expire_time.begin();
  auto it_expire_upper_bound = index_by_expire_time.upper_bound(now);
  while (it_expire != it_expire_upper_bound) {
    if (!(*it_expire).deleted) {
      index_by_expire_time.modify(it_expire,
           std::bind(&KeyValueTuple::UpdateStatus, args::_1,
                     (*it_expire).expire_time, (*it_expire).refresh_time,
                     now + kPendingConfirmDuration,
                     (*it_expire).request_and_signature, true));
    }
    ++it_expire;
  }

  // Fill vector with all entries which have expired refresh times.
  if (!key_value_tuples)
    return;
  auto itr(index_by_refresh_time.begin()),
       upper_bound_itr(index_by_refresh_time.upper_bound(now));
  key_value_tuples->assign(itr, upper_bound_itr);

  // Update refresh times for expired ones.
  if (itr != upper_bound_itr) {
    --(upper_bound_itr);  // Avoid potentially updating entries twice.
    for (;;) {
      bool end(itr == upper_bound_itr);
      if (index_by_refresh_time.modify(itr++,
          std::bind(&KeyValueTuple::set_refresh_time, args::_1,
                    now + kRefreshInterval_))) {
        DLOG(INFO) << debug_id_ << ": Successfully refreshed key "
                   << EncodeToHex((*itr).key_value_signature.key).substr(0, 10);
      } else {
        DLOG(WARNING) << debug_id_ << ": Failed to refresh key "
            << EncodeToHex((*itr).key_value_signature.key).substr(0, 10)
            << " - modify failed.";
      }
      if (end)
        break;
    }
  }
}

bool DataStore::DifferentSigner(
    const KeyValueSignature &key_value_signature,
    const asymm::PublicKey &public_key) const {
  SharedLock shared_lock(shared_mutex_);
  auto it(key_value_index_->get<TagKey>().find(key_value_signature.key));

  if (it == key_value_index_->get<TagKey>().end())
    return false;

  if ((*it).key_value_signature.signature == key_value_signature.signature)
    return false;

  return !asymm::Validate((*it).key_value_signature.value,
                         (*it).key_value_signature.signature,
                         public_key);
}

}  // namespace dht

}  // namespace maidsafe

Added wiki_references/2017/software/MaidSafe_net/src_from_GitHub/the_repository_clones/MaidSafe-DHT/src/maidsafe/dht/data_store.h version [8f905404d8].









































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
/* Copyright (c) 2009 maidsafe.net limited
All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

    * Redistributions of source code must retain the above copyright notice,
    this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright notice,
    this list of conditions and the following disclaimer in the documentation
    and/or other materials provided with the distribution.
    * Neither the name of the maidsafe.net limited nor the names of its
    contributors may be used to endorse or promote products derived from this
    software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#ifndef MAIDSAFE_DHT_DATA_STORE_H_
#define MAIDSAFE_DHT_DATA_STORE_H_

#include <string>
#include <utility>
#include <vector>

#include "boost/date_time/posix_time/posix_time_types.hpp"
#ifdef __MSVC__
#  pragma warning(push)
#  pragma warning(disable: 4244)
#endif
#include "boost/multi_index_container.hpp"
#include "boost/multi_index/ordered_index.hpp"
#include "boost/multi_index/identity.hpp"
#include "boost/multi_index/member.hpp"
#include "boost/multi_index/mem_fun.hpp"
#include "boost/multi_index/composite_key.hpp"
#ifdef __MSVC__
#  pragma warning(pop)
#endif
#include "boost/thread/shared_mutex.hpp"
#include "boost/thread/locks.hpp"

#include "maidsafe/common/rsa.h"

#include "maidsafe/dht/config.h"

namespace bptime = boost::posix_time;


namespace maidsafe {

namespace dht {

namespace test {
class DataStoreTest;
class ServicesTest;
template <typename T>
class RpcsTest;
class NodeImplTest;
class NodeImplTest_FUNC_StoreRefresh_Test;
class NodeImplTest_FUNC_StoreRefreshInvalidSigner_Test;
class NodeImplTest_FUNC_DeleteRefresh_Test;
}

struct KeyValueSignature {
  KeyValueSignature(const std::string &key,
                    const std::string &value,
                    const std::string &signature)
      : key(key),
        value(value),
        signature(signature) {}
  std::string key;
  std::string value;
  std::string signature;
};

typedef std::pair<std::string, std::string> RequestAndSignature;

struct KeyValueTuple {
  KeyValueTuple(const KeyValueSignature &key_value_signature,
                const bptime::ptime &expire_time,
                const bptime::ptime &refresh_time,
                const RequestAndSignature &request_and_signature,
                bool deleted);
  const std::string &key() const;
  const std::string &value() const;
  void set_refresh_time(const bptime::ptime &new_refresh_time);
  void UpdateStatus(const bptime::ptime &new_expire_time,
                    const bptime::ptime &new_refresh_time,
                    const bptime::ptime &new_confirm_time,
                    const RequestAndSignature &new_request_and_signature,
                    bool new_deleted);
  KeyValueSignature key_value_signature;
  bptime::ptime expire_time, refresh_time, confirm_time;
  RequestAndSignature request_and_signature;
  bool deleted;
};

struct TagKey {};
struct TagKeyValue {};
struct TagExpireTime {};
struct TagRefreshTime {};
struct TagConfirmTime {};

typedef boost::multi_index::multi_index_container<
  KeyValueTuple,
  boost::multi_index::indexed_by<
    boost::multi_index::ordered_non_unique<
      boost::multi_index::tag<TagKey>,
      BOOST_MULTI_INDEX_CONST_MEM_FUN(KeyValueTuple, const std::string&, key)
    >,
    boost::multi_index::ordered_unique<
      boost::multi_index::tag<TagKeyValue>,
      boost::multi_index::composite_key<
        KeyValueTuple,
        BOOST_MULTI_INDEX_CONST_MEM_FUN(KeyValueTuple, const std::string&, key),
        BOOST_MULTI_INDEX_CONST_MEM_FUN(KeyValueTuple, const std::string&,
                                        value)
      >
    >,
    boost::multi_index::ordered_non_unique<
      boost::multi_index::tag<TagExpireTime>,
      BOOST_MULTI_INDEX_MEMBER(KeyValueTuple, bptime::ptime, expire_time)
    >,
    boost::multi_index::ordered_non_unique<
      boost::multi_index::tag<TagRefreshTime>,
      BOOST_MULTI_INDEX_MEMBER(KeyValueTuple, bptime::ptime, refresh_time)
    >,
    boost::multi_index::ordered_non_unique<
      boost::multi_index::tag<TagConfirmTime>,
      BOOST_MULTI_INDEX_MEMBER(KeyValueTuple, bptime::ptime, confirm_time)
    >
  >
> KeyValueIndex;

// The time during which an amendment is marked as not confirmed.
const bptime::hours kPendingConfirmDuration(2);


// This class implements physical storage (for data published and fetched via
// the RPCs) for the Kademlia DHT.
// Generally, when a key,value entry is modified, the confirm time for that
// entry is set, and while the confirm time > now, further modifications
// to that key,value can only be made by the holder(s) of the private key used
// to sign the original store request.
class DataStore {
 public:
  explicit DataStore(const bptime::seconds &mean_refresh_interval);
  // Returns whether the key exists in the datastore or not.  This returns true
  // even if the value(s) are marked as deleted.
  bool HasKey(const std::string &key) const;
  // Stores the key, value, signature and marks the expire time as ttl from
  // time of insertion.  Infinite ttl is indicated by bptime::pos_infin.
  // If the value doesn't already exist under key, the k,v,s is added and the
  // method returns kSuccess.
  // If the key and value already exists, is not marked as deleted, and
  // is_refresh is true, the method resets the value's refresh time only (ttl is
  // ignored) and returns kSuccess.
  // If the key and value already exists, is not marked as deleted, and
  // is_refresh is false, the method resets the value's refresh time and ttl and
  // returns kSuccess.
  // If the key and value already exists, is marked as deleted, and is_refresh
  // is true, the method doesn't modify anything and returns kMarkedForDeletion.
  // If the key and value already exists, is marked as deleted, and is_refresh
  // is false, the method sets deleted to false, resets the confirm time and
  // returns kSuccess.
  // NB - DifferentSigner should have been called and returned false before
  // using this method to ensure that only the original signer can modify
  // existing key,values
  int StoreValue(const KeyValueSignature &key_value_signature,
                 const bptime::time_duration &ttl,
                 const RequestAndSignature &store_request_and_signature,
                 bool is_refresh);
  // Marks the key, value, signature as deleted.
  // If the key and value doesn't already exist, and is_refresh is true, the
  // k,v,s is added, marked as deleted and the method returns true.
  // If the key and value doesn't already exist, and is_refresh is false, no
  // action is taken and the method returns true.
  // If the key and value already exists and is marked as deleted, the method
  // resets the value's refresh time only and returns true.
  // If the key and value already exists, is not marked as deleted, confirm time
  // has not expired and is_refresh is true, the method doesn't modify anything
  // and returns false.
  // If the key and value already exists, is not marked as deleted, and
  // is_refresh is false or confirm time has expired, the method sets deleted to
  // true, resets the confirm time and returns true.
  // NB - DifferentSigner should have been called and returned false before
  // using this method to ensure that only the original signer can modify
  // existing key,values
  bool DeleteValue(const KeyValueSignature &key_value_signature,
                   const RequestAndSignature &delete_request_and_signature,
                   bool is_refresh);
  // If any values exist under key and are not marked as deleted, they are added
  // along with the signatures to the vector of pairs and the method returns
  // true.
  bool GetValues(const std::string &key,
                 std::vector<ValueAndSignature> *values_and_signatures) const;
  // Refreshes datastore.  Values which have expired confirm times and which are
  // marked as deleted are removed from the datastore.  Values with expired
  // expire times are marked as deleted.  All values with expired refresh times
  // (whether marked as deleted or not) are returned, and their refresh times
  // updated.
  void Refresh(std::vector<KeyValueTuple> *key_value_tuples);
  // If a value already exists under key, this returns true if its existing
  // signature doesn't match the input one or cannot be validated using
  // public_key.
  bool DifferentSigner(const KeyValueSignature &key_value_signature,
                       const asymm::PublicKey &public_key) const;
  bptime::seconds kRefreshInterval() const { return kRefreshInterval_; }
  void set_debug_id(const std::string &debug_id) { debug_id_ = debug_id; }
  friend class test::DataStoreTest;
  friend class test::ServicesTest;
  template <typename T>
  friend class test::RpcsTest;
  friend class test::NodeImplTest;
  friend class test::NodeImplTest_FUNC_StoreRefresh_Test;
  friend class test::NodeImplTest_FUNC_StoreRefreshInvalidSigner_Test;
  friend class test::NodeImplTest_FUNC_DeleteRefresh_Test;
 private:
  typedef boost::shared_lock<boost::shared_mutex> SharedLock;
  typedef boost::upgrade_lock<boost::shared_mutex> UpgradeLock;
  typedef boost::unique_lock<boost::shared_mutex> UniqueLock;
  typedef boost::upgrade_to_unique_lock<boost::shared_mutex>
      UpgradeToUniqueLock;
  std::shared_ptr<KeyValueIndex> key_value_index_;
  const bptime::seconds kRefreshInterval_;
  mutable boost::shared_mutex shared_mutex_;
  std::string debug_id_;
};

}  // namespace dht

}  // namespace maidsafe

#endif  // MAIDSAFE_DHT_DATA_STORE_H_

Added wiki_references/2017/software/MaidSafe_net/src_from_GitHub/the_repository_clones/MaidSafe-DHT/src/maidsafe/dht/demo/commands.cc version [305c122508].













































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
/* Copyright (c) 2009 maidsafe.net limited
All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

    * Redistributions of source code must retain the above copyright notice,
    this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright notice,
    this list of conditions and the following disclaimer in the documentation
    and/or other materials provided with the distribution.
    * Neither the name of the maidsafe.net limited nor the names of its
    contributors may be used to endorse or promote products derived from this
    software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include "maidsafe/dht/demo/commands.h"

#include <iostream>  // NOLINT

#include "boost/format.hpp"
#include "boost/filesystem.hpp"
#ifdef __MSVC__
#  pragma warning(push)
#  pragma warning(disable: 4127)
#endif
#include "boost/tokenizer.hpp"
#ifdef __MSVC__
#  pragma warning(pop)
#endif
#include "boost/lexical_cast.hpp"
#include "maidsafe/common/crypto.h"
#include "maidsafe/common/utils.h"

#include "maidsafe/dht/log.h"
#include "maidsafe/dht/contact.h"
#include "maidsafe/dht/node_id.h"
#include "maidsafe/dht/node-api.h"

namespace args = std::placeholders;
namespace fs = boost::filesystem;

namespace maidsafe {

namespace dht {

namespace demo {

void PrintNodeInfo(const Contact &contact) {
  ULOG(INFO)
      << boost::format("Node ID:   %1%")
                       % contact.node_id().ToStringEncoded(NodeId::kBase64);
  ULOG(INFO)
      << boost::format("Node IP:   %1%") % contact.endpoint().ip.to_string();
  ULOG(INFO)
      << boost::format("Node port: %1%") % contact.endpoint().port;
  ULOG(INFO)
      << boost::format("Debug ID:  %1%") % DebugId(contact);
}

Commands::Commands(DemoNodePtr demo_node) : demo_node_(demo_node),
                                            null_priv_key_(),
                                            result_arrived_(false),
                                            finish_(false),
                                            wait_mutex_(),
                                            wait_cond_var_(),
                                            mark_results_arrived_() {
  mark_results_arrived_ = std::bind(&Commands::MarkResultArrived, this);
}

void Commands::Run() {
  PrintUsage();
  while (!finish_) {
    std::cout << std::endl << std::endl << "Enter command > ";
    std::string cmdline;
    std::getline(std::cin, cmdline);
    {
      boost::mutex::scoped_lock lock(wait_mutex_);
      ProcessCommand(cmdline);
      wait_cond_var_.wait(lock, std::bind(&Commands::ResultArrived, this));
      result_arrived_ = false;
    }
  }
}

void Commands::Store(const Arguments &args, bool read_from_file) {
  std::string value;
  if (read_from_file) {
    if (args.size() != 3U) {
      ULOG(ERROR) << "Invalid number of arguments for storefile command.";
      return demo_node_->asio_service().post(mark_results_arrived_);
    }
    if (!ReadFile(args[1], &value) || value.empty()) {
      ULOG(ERROR) << "File read error for storefile command.";
      return demo_node_->asio_service().post(mark_results_arrived_);
    }
  } else {
    value = args[1];
  }

  int32_t minutes_to_live(0);
  try {
    minutes_to_live = boost::lexical_cast<int32_t>(args[2]);
  }
  catch(const std::exception &e) {
    ULOG(ERROR) << "Invalid ttl for storefile command." << e.what();
    return demo_node_->asio_service().post(mark_results_arrived_);
  }

  bptime::time_duration ttl;
  if (minutes_to_live == -1)
    ttl = bptime::pos_infin;
  else
    ttl = bptime::minutes(minutes_to_live);

  Key key(args[0], NodeId::kBase64);
  if (!key.IsValid())
    key = Key(crypto::Hash<crypto::SHA512>(args[0]));

  demo_node_->node()->Store(key, value, "", ttl, null_priv_key_,
      std::bind(&Commands::StoreCallback, this, args::_1, key, ttl));
}

void Commands::StoreCallback(const int &result,
                             const NodeId &key,
                             const bptime::time_duration &ttl) {
  if (result != transport::kSuccess) {
    ULOG(ERROR) << "Store operation failed with return code: " << result;
  } else {
    ULOG(INFO) <<
        boost::format("Successfully stored key [ %1% ] with ttl [%2%] min.")
                      % key.ToStringEncoded(NodeId::kBase64) % ttl.minutes();
  }
  demo_node_->asio_service().post(mark_results_arrived_);
}

void Commands::FindValue(const Arguments &args, bool write_to_file) {
  std::string path;
  if (write_to_file) {
    if (args.size() != 2U) {
      ULOG(ERROR) << "Invalid number of arguments for findfile command.";
      return demo_node_->asio_service().post(mark_results_arrived_);
    }
    path = args[1];
  } else {
    if (args.size() != 1U) {
      ULOG(ERROR) << "Invalid number of arguments for findvalue command.";
      return demo_node_->asio_service().post(mark_results_arrived_);
    }
  }

  Key key(std::string(args.at(0)), NodeId::kBase64);
  if (!key.IsValid())
    key = Key(crypto::Hash<crypto::SHA512>(args[0]));

  demo_node_->node()->FindValue(key, null_priv_key_,
      std::bind(&Commands::FindValueCallback, this, args::_1, path));
}

void Commands::FindValueCallback(FindValueReturns find_value_returns,
                                 std::string path) {
  if (find_value_returns.return_code != transport::kSuccess) {
    ULOG(ERROR) << "FindValue operation failed with return code: "
                << find_value_returns.return_code;
  } else {
    ULOG(INFO)
        << boost::format("FindValue returned: %1% value(s), %2% closest "
                         "contact(s).") %
                         find_value_returns.values_and_signatures.size() %
                         find_value_returns.closest_nodes.size();
    if (find_value_returns.cached_copy_holder.node_id().String() !=
        kZeroId) {
      ULOG(INFO)
          << boost::format(
                 "Node holding a cached copy of the value: [ %1% ]")
                 % find_value_returns.cached_copy_holder.node_id().
                 ToStringEncoded(NodeId::kBase64);
    }
    if (find_value_returns.needs_cache_copy.node_id().String() !=
        kZeroId) {
      ULOG(INFO)
          << boost::format("Node needing a cache copy of the values: [ %1% ]")
                % find_value_returns.needs_cache_copy.node_id().
                ToStringEncoded(NodeId::kBase64);
    }
    // Writing only 1st value
    if (!find_value_returns.values_and_signatures.empty()) {
      if (path.empty()) {
        std::string value(find_value_returns.values_and_signatures[0].first);
        ULOG(INFO) << "Value: " << value;
      } else {
        WriteFile(path, find_value_returns.values_and_signatures[0].first);
      }
    }
  }
  demo_node_->asio_service().post(mark_results_arrived_);
}

void Commands::GetContact(const Arguments &args) {
  if (args.size() != 1U) {
    ULOG(ERROR) << "Invalid number of arguments for getcontact command.";
    return demo_node_->asio_service().post(mark_results_arrived_);
  }

  NodeId node_id(args[0], NodeId::kBase64);
  if (!node_id.IsValid()) {
    ULOG(ERROR) << "Invalid Node ID for getcontact command.";
    return demo_node_->asio_service().post(mark_results_arrived_);
  }

  demo_node_->node()->GetContact(node_id,
      std::bind(&Commands::GetContactsCallback, this, args::_1, args::_2));
}

void Commands::GetContactsCallback(const int &result, Contact contact) {
  if (result != transport::kSuccess) {
    ULOG(ERROR) << "GetContacts operation failed with error code: " << result;
  } else {
    ULOG(INFO) << "GetContacts operation successfully returned:";
    PrintNodeInfo(contact);
  }
  demo_node_->asio_service().post(mark_results_arrived_);
}

void Commands::FindNodes(const Arguments &args, bool write_to_file) {
  std::string path;
  if (write_to_file) {
    if (args.size() != 2U) {
      ULOG(ERROR) << "Invalid number of arguments for findnodesfile command.";
      return demo_node_->asio_service().post(mark_results_arrived_);
    }
    path = args[1];
  } else {
    if (args.size() != 1U) {
      ULOG(ERROR) << "Invalid number of arguments for findnodes command.";
      return demo_node_->asio_service().post(mark_results_arrived_);
    }
  }

  NodeId node_id(args[0], NodeId::kBase64);
  if (!node_id.IsValid()) {
    ULOG(ERROR) << "Invalid Node ID.";
    return demo_node_->asio_service().post(mark_results_arrived_);
  }

  demo_node_->node()->FindNodes(node_id,
      std::bind(&Commands::FindNodesCallback, this, args::_1, args::_2, path));
}

void Commands::FindNodesCallback(const int &result,
                                 std::vector<Contact> contacts,
                                 std::string path) {
  if (result != transport::kSuccess) {
    ULOG(ERROR) << "FindNodes operation failed with error code: " << result;
  } else {
    if (path.empty()) {
      ULOG(INFO) << "FindNodes returned the following " << contacts.size()
                << " contact(s):";
      for (auto it = contacts.begin(); it != contacts.end(); ++it)
        ULOG(INFO) << (*it).node_id().ToStringEncoded(NodeId::kBase64);
    } else {
      std::string content;
      for (auto it = contacts.begin(); it != contacts.end(); ++it)
        content += ((*it).node_id().ToStringEncoded(NodeId::kBase64) + "\n");
      WriteFile(path, content);
    }
  }
  demo_node_->asio_service().post(mark_results_arrived_);
}

void Commands::Store50Values(const Arguments &args) {
  if (args.size() != 1U) {
    ULOG(ERROR) << "Invalid number of arguments for store50values command.";
    return demo_node_->asio_service().post(mark_results_arrived_);
  }

  const uint16_t kCount(50);
  const std::string kPrefix(args[0]);
  uint16_t returned_count(0);
  for (uint16_t i = 0; i != kCount; ++i) {
    Key key(crypto::Hash<crypto::SHA512>(kPrefix +
                                         boost::lexical_cast<std::string>(i)));
    std::string key_str = key.ToStringEncoded(NodeId::kBase64);

    std::string value;
    for (int j = 0; j != 102400; ++j)
      value += (kPrefix + boost::lexical_cast<std::string>(i));

    bptime::time_duration ttl(boost::posix_time::pos_infin);
    demo_node_->node()->Store(key, value, "", ttl, null_priv_key_,
        std::bind(&Commands::Store50Callback, this, args::_1, key_str,
                  &returned_count));
  }
  {
    boost::mutex::scoped_lock lock(wait_mutex_);
    while (returned_count != kCount) {
      wait_cond_var_.wait(lock);
    }
  }
  demo_node_->asio_service().post(mark_results_arrived_);
}

void Commands::Store50Callback(const int &result,
                               const std::string &key,
                               uint16_t *returned_count) {
  if (result != transport::kSuccess) {
    ULOG(ERROR) << boost::format("ERROR. Invalid response. Kademlia Store Value"
                                 " key:[ %1% ]") % key;
  } else {
    ULOG(INFO) << boost::format("Successfully stored key [ %1% ]") % key;
  }
  boost::mutex::scoped_lock lock(wait_mutex_);
  ++(*returned_count);
  wait_cond_var_.notify_one();
}

void Commands::PrintUsage() {
  ULOG(INFO) << "\thelp                              Print options.";
  ULOG(INFO) << "\tgetinfo                           Print this node's info.";
  ULOG(INFO) << "\tgetcontact <node_id>              Get contact details of "
             << "node_id.";
  ULOG(INFO) << "\tstorefile <key> <filepath> <ttl>  Store contents of file in "
             << "the network.  ttl in minutes (-1 for infinite).";
  ULOG(INFO) << "\tstorevalue <key> <value> <ttl>    Store value in the "
             << "network.  ttl in minutes (-1 for infinite).";
  ULOG(INFO) << "\tfindfile <key> <filepath>         Find value stored with "
             << "key and save it to filepath.";
  ULOG(INFO) << "\tfindvalue <key>                   Find value stored with "
             << "key.";
  ULOG(INFO) << "\tfindnodes <key>                   Find k closest nodes to "
             << "key.";
  ULOG(INFO) << "\tfindnodesfile <key> <filepath>    Find k closest nodes to "
             << "key and save their IDs to filepath.";
  ULOG(INFO) << "\tstore50values <prefix>            Store 50 key value pairs "
             << "of form (prefix[i], prefix[i]*100).";
//  ULOG(INFO) << "\ttimings                           Print statistics for RPC"
//             << " timings.";
  ULOG(INFO) << "\texit                              Stop the node and exit.";
  ULOG(INFO) << "\tNOTE -- node_id should be base64 encoded.";
  ULOG(INFO) << "\tNOTE -- If key is not a valid 512 hash key (base64 encoded "
             << "format), it will be hashed.";
}

void Commands::ProcessCommand(const std::string &cmdline) {
  if (cmdline.empty()) {
    demo_node_->asio_service().post(mark_results_arrived_);
    return;
  }

  std::string cmd;
  Arguments args;
  try {
    boost::char_separator<char> sep(" ");
    boost::tokenizer<boost::char_separator<char>> tok(cmdline, sep);
    for (auto it = tok.begin(); it != tok.end(); ++it) {
      if (it == tok.begin())
        cmd = *it;
      else
        args.push_back(*it);
    }
  }
  catch(const std::exception &e) {
    ULOG(ERROR) << "Error processing command: " << e.what();
    demo_node_->asio_service().post(mark_results_arrived_);
  }

  if (cmd == "help") {
    PrintUsage();
    demo_node_->asio_service().post(mark_results_arrived_);
  } else if (cmd == "getinfo") {
    PrintNodeInfo(demo_node_->node()->contact());
    demo_node_->asio_service().post(mark_results_arrived_);
  } else if (cmd == "getcontact") {
    GetContact(args);
  } else if (cmd == "storefile") {
    Store(args, true);
  } else if (cmd == "storevalue") {
    Store(args, false);
  } else if (cmd == "findvalue") {
    FindValue(args, false);
  } else if (cmd == "findfile") {
    FindValue(args, true);
  } else if (cmd == "findnodes") {
    FindNodes(args, false);
  } else if (cmd == "findnodesfile") {
    FindNodes(args, true);
  } else if (cmd == "store50values") {
    Store50Values(args);
  } else if (cmd == "exit") {
    ULOG(INFO) << "Exiting application...";
    finish_ = true;
    demo_node_->asio_service().post(mark_results_arrived_);
  } else {
    ULOG(ERROR) << "Invalid command: " << cmd;
    demo_node_->asio_service().post(mark_results_arrived_);
  }
}



void Commands::PrintRpcTimings() {
//  rpcprotocol::RpcStatsMap rpc_timings(chmanager_->RpcTimings());
//  ULOG(INFO) << boost::format("Calls  RPC Name  %40t% min/avg/max\n");
//  for (rpcprotocol::RpcStatsMap::const_iterator it = rpc_timings.begin();
//       it != rpc_timings.end();
//       ++it) {
//  ULOG(INFO) << boost::format("%1% : %2% %40t% %3% / %4% / %5% \n")
//           % it->second.Size()
//           % it->first.c_str()
//           % it->second.Min()  // / 1000.0
//           % it->second.Mean()  // / 1000.0
//           % it->second.Max();  // / 1000.0;
//  }
}

void Commands::MarkResultArrived() {
  boost::mutex::scoped_lock lock(wait_mutex_);
  result_arrived_ = true;
  wait_cond_var_.notify_one();
}


}  // namespace demo

}  // namespace dht

}  // namespace maidsafe

Added wiki_references/2017/software/MaidSafe_net/src_from_GitHub/the_repository_clones/MaidSafe-DHT/src/maidsafe/dht/demo/commands.h version [503915572b].









































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
/* Copyright (c) 2009 maidsafe.net limited
All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

    * Redistributions of source code must retain the above copyright notice,
    this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright notice,
    this list of conditions and the following disclaimer in the documentation
    and/or other materials provided with the distribution.
    * Neither the name of the maidsafe.net limited nor the names of its
    contributors may be used to endorse or promote products derived from this
    software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#ifndef MAIDSAFE_DHT_DEMO_COMMANDS_H_
#define MAIDSAFE_DHT_DEMO_COMMANDS_H_

#include <memory>
#include <string>
#include <vector>

#include "boost/date_time/posix_time/posix_time_types.hpp"
#include "boost/thread/condition_variable.hpp"
#include "boost/thread/mutex.hpp"

#include "maidsafe/dht/config.h"
#include "maidsafe/dht/node-api.h"
#include "maidsafe/dht/node_container.h"

namespace bptime = boost::posix_time;

namespace maidsafe {
namespace dht {

class NodeId;


namespace demo {

void PrintNodeInfo(const Contact &contact);

typedef NodeContainer<Node> DemoNode;
typedef std::shared_ptr<NodeContainer<Node>> DemoNodePtr;

class Commands {
 public:
  explicit Commands(DemoNodePtr demo_node);
  void Run();

 private:
  typedef std::vector<std::string> Arguments;
  void Store(const Arguments &args, bool read_from_file);
  void StoreCallback(const int &result,
                     const NodeId &key,
                     const bptime::time_duration &ttl);
  void FindValue(const Arguments &args, bool write_to_file);
  void FindValueCallback(FindValueReturns find_value_returns, std::string path);
  void GetContact(const Arguments &args);
  void GetContactsCallback(const int &result, Contact contact);
  void FindNodes(const Arguments &args, bool write_to_file);
  void FindNodesCallback(const int &result,
                         std::vector<Contact> contacts,
                         std::string path);
  void Store50Values(const Arguments &args);
  void Store50Callback(const int &result,
                       const std::string &key,
                       uint16_t *returned_count);
  void PrintUsage();
  void ProcessCommand(const std::string &cmdline);
  void PrintRpcTimings();
  void MarkResultArrived();
  bool ResultArrived() { return result_arrived_; }
  std::shared_ptr<DemoNode> demo_node_;
  PrivateKeyPtr null_priv_key_;
  bool result_arrived_, finish_;
  boost::mutex wait_mutex_;
  boost::condition_variable wait_cond_var_;
  std::function<void()> mark_results_arrived_;
};

}  // namespace demo

}  // namespace dht

}  // namespace maidsafe

#endif  // MAIDSAFE_DHT_DEMO_COMMANDS_H_

Added wiki_references/2017/software/MaidSafe_net/src_from_GitHub/the_repository_clones/MaidSafe-DHT/src/maidsafe/dht/demo/demo_main.cc version [e2c94a3379].









































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
/* Copyright (c) 2009 maidsafe.net limited
All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

    * Redistributions of source code must retain the above copyright notice,
    this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright notice,
    this list of conditions and the following disclaimer in the documentation
    and/or other materials provided with the distribution.
    * Neither the name of the maidsafe.net limited nor the names of its
    contributors may be used to endorse or promote products derived from this
    software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include <signal.h>
#include "boost/filesystem.hpp"
#include "boost/program_options.hpp"

#ifndef __APPLE__
  #include "maidsafe/common/breakpad.h"
#endif
#include "maidsafe/common/crypto.h"
#include "maidsafe/common/utils.h"

#ifdef __MSVC__
#  pragma warning(push)
#  pragma warning(disable: 4127 4244 4267)
#endif
#include "maidsafe/dht/kademlia.pb.h"
#ifdef __MSVC__
#  pragma warning(pop)
#endif
#include "maidsafe/dht/config.h"
#include "maidsafe/dht/contact.h"
#include "maidsafe/dht/demo/commands.h"
#include "maidsafe/dht/log.h"
#include "maidsafe/dht/node-api.h"
#include "maidsafe/dht/node_container.h"
#include "maidsafe/dht/node_id.h"
#include "maidsafe/dht/return_codes.h"
#include "maidsafe/dht/utils.h"
#include "maidsafe/dht/version.h"


namespace bptime = boost::posix_time;
namespace fs = boost::filesystem;
namespace po = boost::program_options;
namespace mk = maidsafe::dht;
namespace mt = maidsafe::transport;
namespace ma = maidsafe::asymm;

struct PortRange {
  PortRange(uint16_t first, uint16_t second)
      : first(first), second(second) {}
  uint16_t first;
  uint16_t second;
};

namespace {

void ConflictingOptions(const po::variables_map &variables_map,
                        const char *opt1,
                        const char *opt2) {
  if (variables_map.count(opt1) && !variables_map[opt1].defaulted()
      && variables_map.count(opt2) && !variables_map[opt2].defaulted()) {
    throw std::logic_error(std::string("Conflicting options '") + opt1 +
                           "' and '" + opt2 + "'.");
  }
}

// Function used to check that if 'for_what' is specified, then
// 'required_option' is specified too.
void OptionDependency(const po::variables_map &variables_map,
                      const char *for_what,
                      const char *required_option) {
  if (variables_map.count(for_what) && !variables_map[for_what].defaulted()) {
    if (variables_map.count(required_option) == 0 ||
        variables_map[required_option].defaulted()) {
      throw std::logic_error(std::string("Option '") + for_what
                             + "' requires option '" + required_option + "'.");
    }
  }
}

volatile bool ctrlc_pressed(false);

void CtrlCHandler(int /*a*/) {
  ctrlc_pressed = true;
}

mk::Contact ComposeContact(const mk::NodeId &node_id,
                           const mt::Endpoint &endpoint) {
  std::vector<mt::Endpoint> local_endpoints;
  local_endpoints.push_back(endpoint);
  mk::Contact contact(node_id, endpoint, local_endpoints, endpoint, false,
                      false, "", ma::PublicKey(), "");
  return contact;
}

mk::Contact ComposeContactWithKey(
    const mk::NodeId &node_id,
    const mt::Endpoint &endpoint,
    const ma::Keys &crypto_key_pair) {
  std::vector<mt::Endpoint> local_endpoints;
  local_endpoints.push_back(endpoint);
  mk::Contact contact(node_id, endpoint, local_endpoints, endpoint, false,
                      false, node_id.String(), crypto_key_pair.public_key, "");
  return contact;
}

}  // unnamed namespace

void validate(boost::any& v, const std::vector<std::string>& values,
              PortRange*, int) {
  PortRange port_range(0, 0);
  if (values.size() == 1) {
    try {
      std::string arg = boost::lexical_cast<std::string>(values.at(0));
      if (arg.compare("auto") == 0 || arg.compare("AUTO") == 0) {  // auto
        port_range.first = 8000;
        port_range.second = 65535;
      } else if (arg.find("-") != std::string::npos) {  // port range
        boost::char_separator<char> sep("-");
        boost::tokenizer<boost::char_separator<char>> tok(arg, sep);
        auto it = tok.begin();
        port_range.first = boost::lexical_cast<uint16_t>(*it);
        ++it;
        if (it == tok.end()) {
          throw po::validation_error(po::validation_error::invalid_option);
        }
        port_range.second = boost::lexical_cast<uint16_t>(*it);
        ++it;
        if (it != tok.end()) {
          throw po::validation_error(po::validation_error::invalid_option);
        }
      } else {  // specific port
        port_range.first = boost::lexical_cast<uint16_t>(arg);
        port_range.second = boost::lexical_cast<uint16_t>(arg);
      }
    }
    catch(boost::bad_lexical_cast&) {
      throw po::validation_error(po::validation_error::invalid_option);
    }
  } else {
    throw po::validation_error(po::validation_error::invalid_option,
                               "Invalid port or port range");
  }

  if (port_range.first > port_range.second || port_range.first < 8000) {
    throw po::validation_error(po::validation_error::invalid_option,
                               "Invalid port range");
  }
  v = port_range;
}

int main(int argc, char **argv) {
  maidsafe::InitLogging(argv[0]);
#ifndef __APPLE__
  fs::path cur_path = fs::initial_path();
  maidsafe::crash_report::ProjectInfo current_project("MaidSafe-DHT",
                        boost::lexical_cast<std::string>(MAIDSAFE_DHT_VERSION));
#ifdef WIN32
  google_breakpad::ExceptionHandler exception_handler(cur_path.wstring(),
                                        nullptr,
                                        maidsafe::crash_report::DumpCallback,
                                        &current_project,
                                        true);
#else
  google_breakpad::ExceptionHandler exception_handler(cur_path.string(),
                                        nullptr,
                                        maidsafe::crash_report::DumpCallback,
                                        &current_project,
                                        true);
#endif
#endif
  try {
    PortRange port_range(8000, 65535);
    std::string logfile, bootstrap_file("bootstrap_contacts");
    uint16_t k(4), alpha(3), beta(2);
    std::string ip("127.0.0.1");
    uint32_t refresh_interval(3600);
    size_t thread_count(3);
    po::options_description options_description("Options");
    options_description.add_options()
        ("help,h", "Print options.")
        ("version,V", "Print program version.")
        ("logfile,l", po::value(&logfile), "Path of log file.")
        ("verbose,v", po::bool_switch(), "Verbose logging to console and file.")
//        ("kadconfigfile,g",
//          po::value(&kadconfigpath)->default_value(kadconfigpath),
//          "Complete pathname of kadconfig file. Default is Node<port>/."
//          "kadconfig")
        ("client,c", po::bool_switch(), "Start the node as a client node.")
        ("first_node,f", po::bool_switch(), "Start the node as the first one of"
            " a new network.")
//        ("type,t", po::value(&type)->default_value(type),
//            "Type of transport: 0 - TCP (default), 1 - UDP, 2 - Other.")
//        ("port,p", po::value(&listening_port)->default_value(listening_port),
//            "Local listening port of node (applicable to non-client type "
//            "only).")
        ("port,p", po::value<PortRange>(&port_range)->multitoken(),
              "Local listening port/port-range to start non-client type node."
              "Use auto for any port.")
        ("bootstrap,b", po::value<std::string>
            (&bootstrap_file)->default_value(bootstrap_file),
            "Path to XML file with bootstrap nodes.")
        ("k,k", po::value(&k)->default_value(k),
            "Kademlia k; default number of contacts returned from a lookup.")
        ("alpha,a", po::value(&alpha)->default_value(alpha),
            "Kademlia alpha; parallel level of Find RPCs.")
        ("beta", po::value(&beta)->default_value(beta),
            "Kademlia beta; number of returned Find RPCs required to start a "
            "subsequent iteration.")
//        ("upnp", po::bool_switch(), "Use UPnP for Nat Traversal.")
//        ("port_fw", po::bool_switch(), "Manually port forwarded local port.")
//        ("secure", po::bool_switch(),
//            "Node with keys. Can only communicate with other secure nodes")
        ("thread_count", po::value(&thread_count)->default_value(thread_count),
            "Number of worker threads.")
        ("noconsole", po::bool_switch(),
            "Disable access to Kademlia functions (store, findvalue, "
            "findnode, etc.) after node startup.")
//        ("nodeinfopath", po::value(&thisnodekconfigpath),
//        "Writes to this path a kadconfig file (with name .kadconfig) with "
//          "this node's information.")
        ("refresh_interval,r",
            po::value(&refresh_interval)->default_value(refresh_interval / 60),
            "Average time between value refreshes (in minutes).");

    po::variables_map variables_map;
    po::store(po::parse_command_line(argc, argv, options_description),
              variables_map);


    if (variables_map.count("help")) {
      std::cout << options_description << std::endl;
      return 0;
    }

    if (variables_map.count("version")) {
      std::cout << "MaidSafe-DHT "
                << maidsafe::GetMaidSafeVersion(MAIDSAFE_DHT_VERSION)
                << std::endl;
      return 0;
    }

//    ConflictingOptions(variables_map, "upnp", "port_fw");
    ConflictingOptions(variables_map, "client", "noconsole");
    ConflictingOptions(variables_map, "first_node", "bootstrap_file");

    // Set up logging
    if (variables_map["verbose"].as<bool>()) {
      FLAGS_ms_logging_common = google::INFO;
      FLAGS_ms_logging_transport = google::INFO;
      FLAGS_ms_logging_dht = google::INFO;
    } else {
      FLAGS_ms_logging_common = google::FATAL;
      FLAGS_ms_logging_transport = google::FATAL;
      FLAGS_ms_logging_dht = google::FATAL;
    }
    FLAGS_log_prefix = variables_map["verbose"].as<bool>();
    FLAGS_ms_logging_user = google::INFO;
    FLAGS_logtostderr = true;
    if (variables_map.count("logfile")) {
      fs::path log_path;
      try {
        log_path = fs::path(variables_map["logfile"].as<std::string>());
        if (!fs::exists(log_path.parent_path()) &&
            !fs::create_directories(log_path.parent_path())) {
          ULOG(ERROR) << "Could not create directory for log file.";
          log_path = fs::temp_directory_path() / "kademlia_demo.log";
        }
      }
      catch(const std::exception &e) {
        ULOG(ERROR) << "Error creating directory for log file: " << e.what();
        boost::system::error_code error_code;
        log_path = fs::temp_directory_path(error_code) / "kademlia_demo.log";
      }

      ULOG(INFO) << "Log file at " << log_path;
      for (google::LogSeverity severity(google::WARNING);
           severity != google::NUM_SEVERITIES; ++severity) {
        google::SetLogDestination(severity, "");
      }
      google::SetLogDestination(google::INFO, log_path.string().c_str());
      FLAGS_alsologtostderr = true;
    }

    // Set up DemoNode
    bool first_node(variables_map["first_node"].as<bool>());
    fs::path bootstrap_file_path(bootstrap_file);
    if (variables_map.count("bootstrap")) {
      bootstrap_file_path =
          fs::path(variables_map["bootstrap"].as<std::string>());
    }
    std::vector<maidsafe::dht::Contact> bootstrap_contacts;
    if (!first_node) {
      if (!ReadContactsFromFile(bootstrap_file_path, &bootstrap_contacts)) {
         return 1;
      }
      if (bootstrap_contacts.empty()) {
        LOG(ERROR) << "No contacts found in bootstrap contacts file.";
        return 1;
      }
    }

    thread_count = variables_map["thread_count"].as<size_t>();
    if (thread_count > 100) {
      ULOG(WARNING) << "Too many threads.  Setting thread count to 3.";
      thread_count = 3;
    }

    bool client_only_node(variables_map["client"].as<bool>());

//    type = (variables_map["type"].as<int>());
//    if (type > 2) {
//      ULOG(ERROR) << "Invalid transport type.  Choose 0, 1 or 2.";
//      return 1;
//    }


    if (variables_map.count("refresh_interval")) {
      refresh_interval = variables_map["refresh_interval"].as<uint32_t>();
      refresh_interval = refresh_interval * 60;
    } else {
      refresh_interval = 3600;
    }
    bptime::seconds mean_refresh_interval(refresh_interval);

//    bool secure(variables_map["secure"].as<bool>());


    mk::demo::DemoNodePtr demo_node(new mk::demo::DemoNode);
    ULOG(INFO) << "Creating node...";
    demo_node->Init(static_cast<uint8_t>(thread_count), mk::KeyPairPtr(),
                    mk::MessageHandlerPtr(), client_only_node, k, alpha, beta,
                    mean_refresh_interval);
    std::pair<uint16_t, uint16_t> ports(port_range.first, port_range.second);
    int result = demo_node->Start(bootstrap_contacts, ports);

    if (first_node)
      demo_node->node()->GetBootstrapContacts(&bootstrap_contacts);

    WriteContactsToFile(bootstrap_file_path, &bootstrap_contacts);

    if (result != mk::kSuccess) {
      ULOG(ERROR) << "Node failed to join the network with return code "
                  << result;
      demo_node->Stop(nullptr);
      return result;
    }

    mk::demo::PrintNodeInfo(demo_node->node()->contact());

    if (!variables_map["noconsole"].as<bool>()) {
      mk::demo::Commands commands(demo_node);
      commands.Run();
    } else {
      ULOG(INFO) << "===============================";
      ULOG(INFO) << "     Press Ctrl+C to exit.";
      ULOG(INFO) << "===============================";
      signal(SIGINT, CtrlCHandler);
      while (!ctrlc_pressed)
        maidsafe::Sleep(boost::posix_time::seconds(1));
    }
    bootstrap_contacts.clear();
    demo_node->Stop(&bootstrap_contacts);
    ULOG(INFO) << "Node stopped successfully.";
  }
  catch(const std::exception &e) {
    ULOG(ERROR) << "Error: " << e.what();
    return mk::kGeneralError;
  }
  return mk::kSuccess;
}

Added wiki_references/2017/software/MaidSafe_net/src_from_GitHub/the_repository_clones/MaidSafe-DHT/src/maidsafe/dht/kademlia.proto version [348446aac4].

















































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package maidsafe.dht.protobuf;

message Endpoint {
  required bytes ip = 1;
  required int32 port = 2;
}

message Contact {
  optional Endpoint endpoint = 1;
  repeated bytes local_ips = 2;
  optional int32 local_port = 3;
  optional Endpoint rendezvous = 4;
  optional bool tcp443 = 5;
  optional bool tcp80 = 6;
  optional bool prefer_local = 7;
  required bytes node_id = 8;
  optional bytes public_key_id = 9;
  optional bytes public_key = 10;
  optional bytes other_info = 11;
}

message BootstrapContacts {
  repeated Contact contact = 1;
}

Added wiki_references/2017/software/MaidSafe_net/src_from_GitHub/the_repository_clones/MaidSafe-DHT/src/maidsafe/dht/log.h version [6703da6626].















































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/*******************************************************************************
 *  Copyright 2011 maidsafe.net limited                                        *
 *                                                                             *
 *  The following source code is property of maidsafe.net limited and is not   *
 *  meant for external use.  The use of this code is governed by the license   *
 *  file LICENSE.TXT found in the root of this directory and also on           *
 *  www.maidsafe.net.                                                          *
 *                                                                             *
 *  You are not free to copy, amend or otherwise use this source code without  *
 *  the explicit written permission of the board of directors of maidsafe.net. *
 ***************************************************************************//**
 */

#ifndef MAIDSAFE_DHT_LOG_H_
#define MAIDSAFE_DHT_LOG_H_

#include "maidsafe/common/log.h"

#undef LOG
#define LOG(severity) MAIDSAFE_LOG(dht, severity)

#endif  // MAIDSAFE_DHT_LOG_H_

Added wiki_references/2017/software/MaidSafe_net/src_from_GitHub/the_repository_clones/MaidSafe-DHT/src/maidsafe/dht/maidsafe-dht.h version [36b33630c5].











































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
/* Copyright (c) 2009 maidsafe.net limited
All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

    * Redistributions of source code must retain the above copyright notice,
    this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright notice,
    this list of conditions and the following disclaimer in the documentation
    and/or other materials provided with the distribution.
    * Neither the name of the maidsafe.net limited nor the names of its
    contributors may be used to endorse or promote products derived from this
    software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#ifndef MAIDSAFE_DHT_MAIDSAFE_DHT_H_
#define MAIDSAFE_DHT_MAIDSAFE_DHT_H_

#include "maidsafe/transport/transport.h"
#include "maidsafe/transport/message_handler.h"
#include "maidsafe/transport/tcp_transport.h"
#include "maidsafe/transport/udp_transport.h"

#include "maidsafe/dht/kademlia/node-api.h"
#include "maidsafe/dht/kademlia/node_container.h"
#include "maidsafe/dht/kademlia/config.h"
#include "maidsafe/dht/kademlia/contact.h"
#include "maidsafe/dht/kademlia/node_id.h"
#include "maidsafe/dht/kademlia/message_handler.h"
#include "maidsafe/dht/kademlia/rpcs_objects.h"
#include "maidsafe/dht/kademlia/return_codes.h"

#include "maidsafe/dht/version.h"

#if MAIDSAFE_DHT_VERSION != 3200
#  error This API is not compatible with the installed library.\
    Please update the maidsafe-dht library.
#endif


#endif  // MAIDSAFE_DHT_MAIDSAFE_DHT_H_

Added wiki_references/2017/software/MaidSafe_net/src_from_GitHub/the_repository_clones/MaidSafe-DHT/src/maidsafe/dht/message_handler.cc version [be6eff3912].

































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
  /* Copyright (c) 2010 maidsafe.net limited
All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

    * Redistributions of source code must retain the above copyright notice,
    this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright notice,
    this list of conditions and the following disclaimer in the documentation
    and/or other materials provided with the distribution.
    * Neither the name of the maidsafe.net limited nor the names of its
    contributors may be used to endorse or promote products derived from this
    software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include "maidsafe/dht/message_handler.h"

#include "boost/lexical_cast.hpp"

#ifdef __MSVC__
#  pragma warning(push)
#  pragma warning(disable: 4127 4244 4267)
#endif
#include "maidsafe/dht/rpcs.pb.h"
#ifdef __MSVC__
#  pragma warning(pop)
#endif

namespace maidsafe {

namespace dht {

std::string MessageHandler::WrapMessage(
    const protobuf::PingRequest &msg,
    const asymm::PublicKey &recipient_public_key) {
  if (!msg.IsInitialized())
    return "";
  return MakeSerialisedWrapperMessage(kPingRequest, msg.SerializeAsString(),
                                      kAsymmetricEncrypt, recipient_public_key);
}

std::string MessageHandler::WrapMessage(
    const protobuf::PingResponse &msg,
    const asymm::PublicKey &recipient_public_key) {
  if (!msg.IsInitialized())
    return "";
  return MakeSerialisedWrapperMessage(kPingResponse, msg.SerializeAsString(),
                                      kAsymmetricEncrypt, recipient_public_key);
}

std::string MessageHandler::WrapMessage(
    const protobuf::FindValueRequest &msg,
    const asymm::PublicKey &recipient_public_key) {
  if (!msg.IsInitialized())
    return "";
  return MakeSerialisedWrapperMessage(kFindValueRequest,
                                      msg.SerializeAsString(),
                                      kAsymmetricEncrypt, recipient_public_key);
}

std::string MessageHandler::WrapMessage(
    const protobuf::FindValueResponse &msg,
    const asymm::PublicKey &recipient_public_key) {
  if (!msg.IsInitialized())
    return "";
  return MakeSerialisedWrapperMessage(kFindValueResponse,
                                      msg.SerializeAsString(),
                                      kAsymmetricEncrypt,
                                      recipient_public_key);
}

std::string MessageHandler::WrapMessage(
    const protobuf::FindNodesRequest &msg,
    const asymm::PublicKey &recipient_public_key) {
  if (!msg.IsInitialized())
    return "";
  return MakeSerialisedWrapperMessage(kFindNodesRequest,
                                      msg.SerializeAsString(),
                                      kAsymmetricEncrypt,
                                      recipient_public_key);
}

std::string MessageHandler::WrapMessage(
    const protobuf::FindNodesResponse &msg,
    const asymm::PublicKey &recipient_public_key) {
  if (!msg.IsInitialized())
    return "";
  return MakeSerialisedWrapperMessage(kFindNodesResponse,
                                      msg.SerializeAsString(),
                                      kAsymmetricEncrypt,
                                      recipient_public_key);
}

std::string MessageHandler::WrapMessage(
    const protobuf::StoreRequest &msg,
    const asymm::PublicKey &recipient_public_key) {
  if (!msg.IsInitialized())
    return "";
  return MakeSerialisedWrapperMessage(kStoreRequest,
                                      msg.SerializeAsString(),
                                      kSign | kAsymmetricEncrypt,
                                      recipient_public_key);
}

std::string MessageHandler::WrapMessage(
    const protobuf::StoreResponse &msg,
    const asymm::PublicKey &recipient_public_key) {
  if (!msg.IsInitialized())
    return "";
  return MakeSerialisedWrapperMessage(kStoreResponse, msg.SerializeAsString(),
                                      kAsymmetricEncrypt, recipient_public_key);
}

std::string MessageHandler::WrapMessage(
    const protobuf::StoreRefreshRequest &msg,
    const asymm::PublicKey &recipient_public_key) {
  if (!msg.IsInitialized())
    return "";
  return MakeSerialisedWrapperMessage(kStoreRefreshRequest,
                                      msg.SerializeAsString(),
                                      kSign | kAsymmetricEncrypt,
                                      recipient_public_key);
}

std::string MessageHandler::WrapMessage(
    const protobuf::StoreRefreshResponse &msg,
    const asymm::PublicKey &recipient_public_key) {
  if (!msg.IsInitialized())
    return "";
  return MakeSerialisedWrapperMessage(kStoreRefreshResponse,
                                      msg.SerializeAsString(),
                                      kAsymmetricEncrypt,
                                      recipient_public_key);
}

std::string MessageHandler::WrapMessage(
    const protobuf::DeleteRequest &msg,
    const asymm::PublicKey &recipient_public_key) {
  if (!msg.IsInitialized())
    return "";
  return MakeSerialisedWrapperMessage(kDeleteRequest,
                                      msg.SerializeAsString(),
                                      kSign | kAsymmetricEncrypt,
                                      recipient_public_key);
}

std::string MessageHandler::WrapMessage(
    const protobuf::DeleteResponse &msg,
    const asymm::PublicKey &recipient_public_key) {
  if (!msg.IsInitialized())
    return "";
  return MakeSerialisedWrapperMessage(kDeleteResponse, msg.SerializeAsString(),
                                      kAsymmetricEncrypt, recipient_public_key);
}

std::string MessageHandler::WrapMessage(
    const protobuf::DeleteRefreshRequest &msg,
    const asymm::PublicKey &recipient_public_key) {
  if (!msg.IsInitialized())
    return "";
  return MakeSerialisedWrapperMessage(kDeleteRefreshRequest,
                                      msg.SerializeAsString(),
                                      kSign | kAsymmetricEncrypt,
                                      recipient_public_key);
}

std::string MessageHandler::WrapMessage(
    const protobuf::DeleteRefreshResponse &msg,
    const asymm::PublicKey &recipient_public_key) {
  if (!msg.IsInitialized())
    return "";
  return MakeSerialisedWrapperMessage(kDeleteRefreshResponse,
                                      msg.SerializeAsString(),
                                      kAsymmetricEncrypt,
                                      recipient_public_key);
}

std::string MessageHandler::WrapMessage(
    const protobuf::DownlistNotification &msg,
    const asymm::PublicKey &recipient_public_key) {
  if (!msg.IsInitialized())
    return "";
  return MakeSerialisedWrapperMessage(kDownlistNotification,
                                      msg.SerializeAsString(),
                                      kAsymmetricEncrypt,
                                      recipient_public_key);
}

void MessageHandler::ProcessSerialisedMessage(
    const int &message_type,
    const std::string &payload,
    const SecurityType &security_type,
    const std::string &message_signature,
    const transport::Info &info,
    std::string *message_response,
    transport::Timeout* timeout) {
  message_response->clear();
  *timeout = transport::kImmediateTimeout;
  switch (message_type) {
    case kPingRequest: {
      if (security_type != kAsymmetricEncrypt)
        return;
      protobuf::PingRequest request;
      if (request.ParseFromString(payload) && request.IsInitialized()) {
        protobuf::PingResponse response;
        (*on_ping_request_)(info, request, &response, timeout);
        asymm::PublicKey sender_public_key;
        asymm::DecodePublicKey(request.sender().public_key(),
                              &sender_public_key);
        *message_response = WrapMessage(response,
                                        sender_public_key);
      }
      break;
    }
    case kPingResponse: {
      if (security_type != kAsymmetricEncrypt)
        return;
      protobuf::PingResponse response;
      if (response.ParseFromString(payload) && response.IsInitialized())
        (*on_ping_response_)(info, response);
      break;
    }
    case kFindValueRequest: {
      if (security_type != kAsymmetricEncrypt)
        return;
      protobuf::FindValueRequest request;
      if (request.ParseFromString(payload) && request.IsInitialized()) {
        protobuf::FindValueResponse response;
        (*on_find_value_request_)(info, request, &response, timeout);
        asymm::PublicKey sender_public_key;
        asymm::DecodePublicKey(request.sender().public_key(),
                              &sender_public_key);
        *message_response = WrapMessage(response,
                                        sender_public_key);
      }
      break;
    }
    case kFindValueResponse: {
      if (security_type != kAsymmetricEncrypt)
        return;
      protobuf::FindValueResponse response;
      if (response.ParseFromString(payload) && response.IsInitialized())
        (*on_find_value_response_)(info, response);
      break;
    }
    case kFindNodesRequest: {
      if (security_type != kAsymmetricEncrypt)
        return;
      protobuf::FindNodesRequest request;
      if (request.ParseFromString(payload) && request.IsInitialized()) {
        protobuf::FindNodesResponse response;
        (*on_find_nodes_request_)(info, request, &response, timeout);
        asymm::PublicKey sender_public_key;
        asymm::DecodePublicKey(request.sender().public_key(),
                              &sender_public_key);
        *message_response = WrapMessage(response,
                                        sender_public_key);
      }
      break;
    }
    case kFindNodesResponse: {
      if (security_type != kAsymmetricEncrypt)
        return;
      protobuf::FindNodesResponse response;
      if (response.ParseFromString(payload) && response.IsInitialized())
        (*on_find_nodes_response_)(info, response);
      break;
    }
    case kStoreRequest: {
      if ((security_type != (kSign | kAsymmetricEncrypt)) ||
          message_signature.empty())
        return;
      protobuf::StoreRequest request;
      if (request.ParseFromString(payload) && request.IsInitialized()) {
        if (!request.sender().has_node_id())
          return;
        std::string message =
            boost::lexical_cast<std::string>(message_type) + payload;
        std::string public_key_id, public_key, other_info;
        if (request.sender().has_public_key_id())
          public_key_id = request.sender().public_key_id();
        if (request.sender().has_public_key())
          public_key = request.sender().public_key();
        if (request.sender().has_other_info())
          other_info = request.sender().other_info();
        asymm::PublicKey asym_public_key;
        asymm::DecodePublicKey(public_key, &asym_public_key);
        if (!asymm::ValidateKey(asym_public_key))
          return;
        if (!asymm::Validate(message, message_signature, asym_public_key))
          return;
        protobuf::StoreResponse response;
        (*on_store_request_)(info, request, payload, message_signature,
                             &response, timeout);
        asymm::PublicKey sender_public_key;
        asymm::DecodePublicKey(request.sender().public_key(),
                              &sender_public_key);
        *message_response = WrapMessage(response,
                                        sender_public_key);
      }
      break;
    }
    case kStoreResponse: {
      if (security_type != kAsymmetricEncrypt)
        return;
      protobuf::StoreResponse response;
      if (response.ParseFromString(payload) && response.IsInitialized())
        (*on_store_response_)(info, response);
      break;
    }
    case kStoreRefreshRequest: {
      if ((security_type != (kSign | kAsymmetricEncrypt)) ||
          message_signature.empty())
        return;
      protobuf::StoreRefreshRequest request;
      if (request.ParseFromString(payload) && request.IsInitialized()) {
        std::string message =
            boost::lexical_cast<std::string>(message_type) + payload;
        std::string public_key_id, public_key, other_info;
        if (request.sender().has_public_key_id())
          public_key_id = request.sender().public_key_id();
        if (request.sender().has_public_key())
          public_key = request.sender().public_key();
        if (request.sender().has_other_info())
          other_info = request.sender().other_info();
        asymm::PublicKey asym_public_key;
        asymm::DecodePublicKey(public_key, &asym_public_key);
        if (!asymm::ValidateKey(asym_public_key))
          return;
        if (!asymm::Validate(message, message_signature, asym_public_key))
          return;
        protobuf::StoreRefreshResponse response;
        (*on_store_refresh_request_)(info, request, &response, timeout);
        asymm::PublicKey sender_public_key;
        asymm::DecodePublicKey(request.sender().public_key(),
                              &sender_public_key);
        *message_response = WrapMessage(response,
                                        sender_public_key);
      }
      break;
    }
    case kStoreRefreshResponse: {
      if (security_type != kAsymmetricEncrypt)
        return;
      protobuf::StoreRefreshResponse response;
      if (response.ParseFromString(payload) && response.IsInitialized())
        (*on_store_refresh_response_)(info, response);
      break;
    }
    case kDeleteRequest: {
      if ((security_type != (kSign | kAsymmetricEncrypt)) ||
          message_signature.empty())
        return;
      protobuf::DeleteRequest request;
      if (request.ParseFromString(payload) && request.IsInitialized()) {
        if (!request.sender().has_node_id())
          return;
        std::string message =
            boost::lexical_cast<std::string>(message_type) + payload;
        std::string public_key_id, public_key, other_info;
        if (request.sender().has_public_key_id())
          public_key_id = request.sender().public_key_id();
        if (request.sender().has_public_key())
          public_key = request.sender().public_key();
        if (request.sender().has_other_info())
          other_info = request.sender().other_info();
        asymm::PublicKey asym_public_key;
        asymm::DecodePublicKey(public_key, &asym_public_key);
        if (!asymm::ValidateKey(asym_public_key))
          return;
        if (!asymm::Validate(message, message_signature, asym_public_key))
          return;
        protobuf::DeleteResponse response;
        (*on_delete_request_)(info, request, payload, message_signature,
                              &response, timeout);
        asymm::PublicKey sender_public_key;
        asymm::DecodePublicKey(request.sender().public_key(),
                              &sender_public_key);
        *message_response = WrapMessage(response,
                                        sender_public_key);
      }
      break;
    }
    case kDeleteResponse: {
      if (security_type != kAsymmetricEncrypt)
        return;
      protobuf::DeleteResponse response;
      if (response.ParseFromString(payload) && response.IsInitialized())
        (*on_delete_response_)(info, response);
      break;
    }
    case kDeleteRefreshRequest: {
      if ((security_type != (kSign | kAsymmetricEncrypt)) ||
          message_signature.empty())
        return;
      protobuf::DeleteRefreshRequest request;
      if (request.ParseFromString(payload) && request.IsInitialized()) {
        std::string message =
            boost::lexical_cast<std::string>(message_type) + payload;
        std::string public_key_id, public_key, other_info;
        if (request.sender().has_public_key_id())
          public_key_id = request.sender().public_key_id();
        if (request.sender().has_public_key())
          public_key = request.sender().public_key();
        if (request.sender().has_other_info())
          other_info = request.sender().other_info();
        asymm::PublicKey asym_public_key;
        asymm::DecodePublicKey(public_key, &asym_public_key);
        if (!asymm::ValidateKey(asym_public_key))
          return;
        if (!asymm::Validate(message, message_signature, asym_public_key))
          return;
        protobuf::DeleteRefreshResponse response;
        (*on_delete_refresh_request_)(info, request, &response, timeout);
        asymm::PublicKey sender_public_key;
        asymm::DecodePublicKey(request.sender().public_key(),
                              &sender_public_key);
        *message_response = WrapMessage(response,
                                        sender_public_key);
      }
      break;
    }
    case kDeleteRefreshResponse: {
      if (security_type != kAsymmetricEncrypt)
        return;
      protobuf::DeleteRefreshResponse response;
      if (response.ParseFromString(payload) && response.IsInitialized())
        (*on_delete_refresh_response_)(info, response);
      break;
    }
    case kDownlistNotification: {
      if (security_type != kAsymmetricEncrypt)
        return;
      protobuf::DownlistNotification request;
      if (request.ParseFromString(payload) && request.IsInitialized())
        (*on_downlist_notification_)(info, request, timeout);
      break;
    }
    default:
      transport::MessageHandler::ProcessSerialisedMessage(message_type,
                                                          payload,
                                                          security_type,
                                                          message_signature,
                                                          info,
                                                          message_response,
                                                          timeout);
  }
}

}  // namespace dht

}  // namespace maidsafe

Added wiki_references/2017/software/MaidSafe_net/src_from_GitHub/the_repository_clones/MaidSafe-DHT/src/maidsafe/dht/message_handler.h version [73306dea8f].







































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
/* Copyright (c) 2010 maidsafe.net limited
All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

    * Redistributions of source code must retain the above copyright notice,
    this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright notice,
    this list of conditions and the following disclaimer in the documentation
    and/or other materials provided with the distribution.
    * Neither the name of the maidsafe.net limited nor the names of its
    contributors may be used to endorse or promote products derived from this
    software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#ifndef MAIDSAFE_DHT_MESSAGE_HANDLER_H_
#define MAIDSAFE_DHT_MESSAGE_HANDLER_H_

#include <memory>
#include <string>
#include "boost/concept_check.hpp"
#include "boost/signals2/signal.hpp"
#include "maidsafe/transport/message_handler.h"

#include "maidsafe/dht/config.h"
#include "maidsafe/dht/version.h"

#if MAIDSAFE_DHT_VERSION != 3200
#  error This API is not compatible with the installed library.\
    Please update the maidsafe-dht library.
#endif


namespace bs2 = boost::signals2;

namespace maidsafe {

namespace dht {

namespace protobuf {
class PingRequest;
class PingResponse;
class FindValueRequest;
class FindValueResponse;
class FindNodesRequest;
class FindNodesResponse;
class StoreRequest;
class StoreResponse;
class StoreRefreshRequest;
class StoreRefreshResponse;
class DeleteRequest;
class DeleteResponse;
class DeleteRefreshRequest;
class DeleteRefreshResponse;
class UpdateRequest;
class UpdateResponse;
class DownlistNotification;
}  // namespace protobuf

namespace test {
class KademliaMessageHandlerTest_BEH_WrapMessagePingResponse_Test;
class KademliaMessageHandlerTest_BEH_WrapMessageFindValueResponse_Test;
class KademliaMessageHandlerTest_BEH_WrapMessageFindNodesResponse_Test;
class KademliaMessageHandlerTest_BEH_WrapMessageStoreResponse_Test;
class KademliaMessageHandlerTest_BEH_WrapMessageStoreRefreshResponse_Test;
class KademliaMessageHandlerTest_BEH_WrapMessageDeleteResponse_Test;
class KademliaMessageHandlerTest_BEH_WrapMessageDeleteRefreshResponse_Test;
class KademliaMessageHandlerTest_BEH_ProcessSerialisedMessagePingRqst_Test;
class KademliaMessageHandlerTest_BEH_ProcessSerialisedMessagePingRsp_Test;
class KademliaMessageHandlerTest_BEH_ProcessSerialisedMessageFValRqst_Test;
class KademliaMessageHandlerTest_BEH_ProcessSerialisedMessageFValRsp_Test;
class KademliaMessageHandlerTest_BEH_ProcessSerialisedMessageFNodeRqst_Test;
class KademliaMessageHandlerTest_BEH_ProcessSerialisedMessageFNodeRsp_Test;
class KademliaMessageHandlerTest_BEH_ProcessSerialisedMessageStoreRqst_Test;
class KademliaMessageHandlerTest_BEH_ProcessSerialisedMessageStoreRsp_Test;
class KademliaMessageHandlerTest_BEH_ProcessSerialisedMessageStoreRefRqst_Test;
class KademliaMessageHandlerTest_BEH_ProcessSerialisedMessageStoreRefRsp_Test;
class KademliaMessageHandlerTest_BEH_ProcessSerialisedMessageDeleteRqst_Test;
class KademliaMessageHandlerTest_BEH_ProcessSerialisedMessageDeleteRsp_Test;
class KademliaMessageHandlerTest_BEH_ProcessSerialisedMessageDeleteRefRqst_Test;
class KademliaMessageHandlerTest_BEH_ProcessSerialisedMessageDeleteRefRsp_Test;
class KademliaMessageHandlerTest_BEH_ProcessSerialisedMessageDownlist_Test;
class KademliaMessageHandlerTest;
}  // namespace test

// Highest possible message type ID, use as offset for type extensions.
const int kMaxMessageType(transport::kMaxMessageType + 1000);

enum MessageType {
  kPingRequest = transport::kMaxMessageType + 1,
  kPingResponse,
  kFindValueRequest,
  kFindValueResponse,
  kFindNodesRequest,
  kFindNodesResponse,
  kStoreRequest,
  kStoreResponse,
  kStoreRefreshRequest,
  kStoreRefreshResponse,
  kDeleteRequest,
  kDeleteResponse,
  kDeleteRefreshRequest,
  kDeleteRefreshResponse,
  kDownlistNotification
};

class MessageHandler : public transport::MessageHandler {
 public:
  typedef std::shared_ptr<bs2::signal<  // NOLINT
      void(const transport::Info&,
           const protobuf::PingRequest&,
           protobuf::PingResponse*,
           transport::Timeout*)>> PingReqSigPtr;

  typedef std::shared_ptr<bs2::signal<  // NOLINT
      void(const transport::Info&,
           const protobuf::PingResponse&)>> PingRspSigPtr;

  typedef std::shared_ptr<bs2::signal<  // NOLINT
      void(const transport::Info&,
           const protobuf::FindValueRequest&,
           protobuf::FindValueResponse*,
           transport::Timeout*)>> FindValueReqSigPtr;

  typedef std::shared_ptr<bs2::signal<  // NOLINT
      void(const transport::Info&,
           const protobuf::FindValueResponse&)>> FindValueRspSigPtr;

  typedef std::shared_ptr<bs2::signal<  // NOLINT
      void(const transport::Info&,
           const protobuf::FindNodesRequest&,
           protobuf::FindNodesResponse*,
           transport::Timeout*)>> FindNodesReqSigPtr;

  typedef std::shared_ptr<bs2::signal<  // NOLINT
      void(const transport::Info&,
           const protobuf::FindNodesResponse&)>> FindNodesRspSigPtr;

  typedef std::shared_ptr<bs2::signal<  // NOLINT
      void(const transport::Info&,
           const protobuf::StoreRequest&,
           const std::string&,
           const std::string&,
           protobuf::StoreResponse*,
           transport::Timeout*)>> StoreReqSigPtr;

  typedef std::shared_ptr<bs2::signal<  // NOLINT
      void(const transport::Info&,
           const protobuf::StoreResponse&)>> StoreRspSigPtr;

  typedef std::shared_ptr<bs2::signal<  // NOLINT
      void(const transport::Info&,
           const protobuf::StoreRefreshRequest&,
           protobuf::StoreRefreshResponse*,
           transport::Timeout*)>> StoreRefreshReqSigPtr;

  typedef std::shared_ptr<bs2::signal<  // NOLINT
      void(const transport::Info&,
           const protobuf::StoreRefreshResponse&)>> StoreRefreshRspSigPtr;

  typedef std::shared_ptr<bs2::signal<  // NOLINT
      void(const transport::Info&,
           const protobuf::DeleteRequest&,
           const std::string&,
           const std::string&,
           protobuf::DeleteResponse*,
           transport::Timeout*)>> DeleteReqSigPtr;

  typedef std::shared_ptr<bs2::signal<  // NOLINT
      void(const transport::Info&,
           const protobuf::DeleteResponse&)>> DeleteRspSigPtr;

  typedef std::shared_ptr<bs2::signal<  // NOLINT
      void(const transport::Info&,
           const protobuf::DeleteRefreshRequest&,
           protobuf::DeleteRefreshResponse*,
           transport::Timeout*)>> DeleteRefreshReqSigPtr;

  typedef std::shared_ptr<bs2::signal<  // NOLINT
      void(const transport::Info&,
           const protobuf::DeleteRefreshResponse&)>> DeleteRefreshRspSigPtr;

  typedef std::shared_ptr<bs2::signal<  // NOLINT
      void(const transport::Info&,
           const protobuf::DownlistNotification&,
           transport::Timeout*)>> DownlistNtfSigPtr;

  explicit MessageHandler(PrivateKeyPtr private_key)
    : transport::MessageHandler(private_key),
      on_ping_request_(new PingReqSigPtr::element_type),
      on_ping_response_(new PingRspSigPtr::element_type),
      on_find_value_request_(new FindValueReqSigPtr::element_type),
      on_find_value_response_(new FindValueRspSigPtr::element_type),
      on_find_nodes_request_(new FindNodesReqSigPtr::element_type),
      on_find_nodes_response_(new FindNodesRspSigPtr::element_type),
      on_store_request_(new StoreReqSigPtr::element_type),
      on_store_response_(new StoreRspSigPtr::element_type),
      on_store_refresh_request_(new StoreRefreshReqSigPtr::element_type),
      on_store_refresh_response_(new StoreRefreshRspSigPtr::element_type),
      on_delete_request_(new DeleteReqSigPtr::element_type),
      on_delete_response_(new DeleteRspSigPtr::element_type),
      on_delete_refresh_request_(new DeleteRefreshReqSigPtr::element_type),
      on_delete_refresh_response_(new DeleteRefreshRspSigPtr::element_type),
      on_downlist_notification_(new DownlistNtfSigPtr::element_type) {}
  virtual ~MessageHandler() {}

  std::string WrapMessage(const protobuf::PingRequest &msg,
                          const asymm::PublicKey &recipient_public_key);
  std::string WrapMessage(const protobuf::FindValueRequest &msg,
                          const asymm::PublicKey &recipient_public_key);
  std::string WrapMessage(const protobuf::FindNodesRequest &msg,
                          const asymm::PublicKey &recipient_public_key);
  std::string WrapMessage(const protobuf::StoreRequest &msg,
                          const asymm::PublicKey &recipient_public_key);
  std::string WrapMessage(const protobuf::StoreRefreshRequest &msg,
                          const asymm::PublicKey &recipient_public_key);
  std::string WrapMessage(const protobuf::DeleteRequest &msg,
                          const asymm::PublicKey &recipient_public_key);
  std::string WrapMessage(const protobuf::DeleteRefreshRequest &msg,
                          const asymm::PublicKey &recipient_public_key);
  std::string WrapMessage(const protobuf::DownlistNotification &msg,
                          const asymm::PublicKey &recipient_public_key);

  PingReqSigPtr on_ping_request() { return on_ping_request_; }
  PingRspSigPtr on_ping_response() { return on_ping_response_; }
  FindValueReqSigPtr on_find_value_request() { return on_find_value_request_; }
  FindValueRspSigPtr on_find_value_response() {
    return on_find_value_response_;
  }
  FindNodesReqSigPtr on_find_nodes_request() { return on_find_nodes_request_; }
  FindNodesRspSigPtr on_find_nodes_response() {
    return on_find_nodes_response_;
  }
  StoreReqSigPtr on_store_request() { return on_store_request_; }
  StoreRspSigPtr on_store_response() { return on_store_response_; }
  StoreRefreshReqSigPtr on_store_refresh_request() {
    return on_store_refresh_request_;
  }
  StoreRefreshRspSigPtr on_store_refresh_response() {
    return on_store_refresh_response_;
  }
  DeleteReqSigPtr on_delete_request() { return on_delete_request_; }
  DeleteRspSigPtr on_delete_response() { return on_delete_response_; }
  DeleteRefreshReqSigPtr on_delete_refresh_request() {
    return on_delete_refresh_request_;
  }
  DeleteRefreshRspSigPtr on_delete_refresh_response() {
    return on_delete_refresh_response_;
  }
  DownlistNtfSigPtr on_downlist_notification() {
    return on_downlist_notification_;
  }

 protected:
  virtual void ProcessSerialisedMessage(const int &message_type,
                                        const std::string &payload,
                                        const SecurityType &security_type,
                                        const std::string &message_signature,
                                        const transport::Info &info,
                                        std::string *message_response,
                                        transport::Timeout *timeout);

 private:
  friend class test::KademliaMessageHandlerTest_BEH_WrapMessagePingResponse_Test;  // NOLINT
  friend class test::KademliaMessageHandlerTest_BEH_WrapMessageFindValueResponse_Test;  // NOLINT
  friend class test::KademliaMessageHandlerTest_BEH_WrapMessageFindNodesResponse_Test;  // NOLINT
  friend class test::KademliaMessageHandlerTest_BEH_WrapMessageStoreResponse_Test;  // NOLINT
  friend class test::KademliaMessageHandlerTest_BEH_WrapMessageStoreRefreshResponse_Test;  // NOLINT
  friend class test::KademliaMessageHandlerTest_BEH_WrapMessageDeleteResponse_Test;  // NOLINT
  friend class test::KademliaMessageHandlerTest_BEH_WrapMessageDeleteRefreshResponse_Test;  // NOLINT
  friend class test::KademliaMessageHandlerTest_BEH_ProcessSerialisedMessagePingRqst_Test;  // NOLINT
  friend class test::KademliaMessageHandlerTest_BEH_ProcessSerialisedMessagePingRsp_Test;  // NOLINT
  friend class test::KademliaMessageHandlerTest_BEH_ProcessSerialisedMessageFValRqst_Test;  // NOLINT
  friend class test::KademliaMessageHandlerTest_BEH_ProcessSerialisedMessageFValRsp_Test;  // NOLINT
  friend class test::KademliaMessageHandlerTest_BEH_ProcessSerialisedMessageFNodeRqst_Test;  // NOLINT
  friend class test::KademliaMessageHandlerTest_BEH_ProcessSerialisedMessageFNodeRsp_Test;  // NOLINT
  friend class test::KademliaMessageHandlerTest_BEH_ProcessSerialisedMessageStoreRqst_Test;  // NOLINT
  friend class test::KademliaMessageHandlerTest_BEH_ProcessSerialisedMessageStoreRsp_Test;  // NOLINT
  friend class test::KademliaMessageHandlerTest_BEH_ProcessSerialisedMessageStoreRefRqst_Test;  // NOLINT
  friend class test::KademliaMessageHandlerTest_BEH_ProcessSerialisedMessageStoreRefRsp_Test;  // NOLINT
  friend class test::KademliaMessageHandlerTest_BEH_ProcessSerialisedMessageDeleteRqst_Test;  // NOLINT
  friend class test::KademliaMessageHandlerTest_BEH_ProcessSerialisedMessageDeleteRsp_Test;  // NOLINT
  friend class test::KademliaMessageHandlerTest_BEH_ProcessSerialisedMessageDeleteRefRqst_Test;  // NOLINT
  friend class test::KademliaMessageHandlerTest_BEH_ProcessSerialisedMessageDeleteRefRsp_Test;  // NOLINT
  friend class test::KademliaMessageHandlerTest_BEH_ProcessSerialisedMessageDownlist_Test;  // NOLINT
  friend class test::KademliaMessageHandlerTest;

  MessageHandler(const MessageHandler&);
  MessageHandler& operator=(const MessageHandler&);

  std::string WrapMessage(const protobuf::PingResponse &msg,
                          const asymm::PublicKey &recipient_public_key);
  std::string WrapMessage(const protobuf::FindValueResponse &msg,
                          const asymm::PublicKey &recipient_public_key);
  std::string WrapMessage(const protobuf::FindNodesResponse &msg,
                          const asymm::PublicKey &recipient_public_key);
  std::string WrapMessage(const protobuf::StoreResponse &msg,
                          const asymm::PublicKey &recipient_public_key);
  std::string WrapMessage(const protobuf::StoreRefreshResponse &msg,
                          const asymm::PublicKey &recipient_public_key);
  std::string WrapMessage(const protobuf::DeleteResponse &msg,
                          const asymm::PublicKey &recipient_public_key);
  std::string WrapMessage(const protobuf::DeleteRefreshResponse &msg,
                          const asymm::PublicKey &recipient_public_key);

  PingReqSigPtr on_ping_request_;
  PingRspSigPtr on_ping_response_;
  FindValueReqSigPtr on_find_value_request_;
  FindValueRspSigPtr on_find_value_response_;
  FindNodesReqSigPtr on_find_nodes_request_;
  FindNodesRspSigPtr on_find_nodes_response_;
  StoreReqSigPtr on_store_request_;
  StoreRspSigPtr on_store_response_;
  StoreRefreshReqSigPtr on_store_refresh_request_;
  StoreRefreshRspSigPtr on_store_refresh_response_;
  DeleteReqSigPtr on_delete_request_;
  DeleteRspSigPtr on_delete_response_;
  DeleteRefreshReqSigPtr on_delete_refresh_request_;
  DeleteRefreshRspSigPtr on_delete_refresh_response_;
  DownlistNtfSigPtr on_downlist_notification_;
};

}  // namespace dht

}  // namespace maidsafe

#endif  // MAIDSAFE_DHT_MESSAGE_HANDLER_H_

Added wiki_references/2017/software/MaidSafe_net/src_from_GitHub/the_repository_clones/MaidSafe-DHT/src/maidsafe/dht/node-api.h version [826e20a9e5].



































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
/* Copyright (c) 2009 maidsafe.net limited
All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

    * Redistributions of source code must retain the above copyright notice,
    this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright notice,
    this list of conditions and the following disclaimer in the documentation
    and/or other materials provided with the distribution.
    * Neither the name of the maidsafe.net limited nor the names of its
    contributors may be used to endorse or promote products derived from this
    software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

/*******************************************************************************
 * NOTE: This API is unlikely to have any breaking changes applied.  However,  *
 *       it should not be regarded as a final API until this notice is removed.*
 ******************************************************************************/

#ifndef MAIDSAFE_DHT_NODE_API_H_
#define MAIDSAFE_DHT_NODE_API_H_

#include <cstdint>
#include <memory>
#include <string>
#include <vector>

#include "boost/asio/io_service.hpp"
#include "boost/date_time/posix_time/posix_time_types.hpp"

#include "maidsafe/common/version.h"

#include "maidsafe/dht/contact.h"
#include "maidsafe/dht/config.h"
#include "maidsafe/dht/version.h"

#if MAIDSAFE_DHT_VERSION != 3200
#  error This API is not compatible with the installed library.\
    Please update the maidsafe-dht library.
#endif


namespace maidsafe {

namespace dht {

class NodeImpl;

// This class represents a kademlia node providing the API to join the network,
// find nodes and values, store, delete and update values, as well as the
// methods to access the local storage of the node and its routing table.
class Node {
 public:
  // asio_service is a reference to a boost::asio::io_service instance which
  // should have at least 1 thread running io_service::run().
  //
  // listening_transport is responsible for listening only, not sending.  It
  // need not be listening before it is passed, it will be started in Join.
  //
  // default_securifier is responsible for signing, verification, encrypting and
  // decrypting messages and values.  If it is an invalid pointers, a basic
  // instantiation will be made.  For all other member functions where a
  // securifer is passed, if it is invalid, this default_securifier will be used
  // instead.
  //
  // client_only_node specifies whether the node should be treated as a client
  // on the network rather than a full peer.  In client mode, the node does not
  // accept store requests and is not added to other nodes' routing tables.
  //
  // k, alpha and beta are as defined for standard Kademlia, i.e. number of
  // contacts returned from a Find RPC, parallel level of Find RPCs, and number
  // of returned Find RPCs required to start a subsequent iteration
  // respectively.
  //
  // mean_refresh_interval indicates the average interval between calls to
  // refresh values.
  Node(boost::asio::io_service &asio_service,                 // NOLINT (Fraser)
       TransportPtr listening_transport,
       MessageHandlerPtr message_handler,
       KeyPairPtr default_key_pair,
       bool client_only_node,
       const uint16_t &k,
       const uint16_t &alpha,
       const uint16_t &beta,
       const boost::posix_time::time_duration &mean_refresh_interval);

  ~Node();

  // Join the network.  If the listening_transport cannot be started (or is not
  // already started) on the desired port, the callback indicates failure.
  // bootstrap_contacts should be directly-connected peers to allow successful
  // NAT detection.
  void Join(const NodeId &node_id,
            std::vector<Contact> bootstrap_contacts,
            JoinFunctor callback);

  // Leave the kademlia network.  All values stored in the node are erased and
  // all directly-connected nodes from the routing table are passed into
  // bootstrap_contacts.
  void Leave(std::vector<Contact> *bootstrap_contacts);

  // Store <key,value,signature> for ttl.  Infinite ttl is indicated by
  // boost::posix_time::pos_infin.  If signature is empty, the value is signed
  // using securifier, unless it is invalid, in which case the node's
  // default_securifier signs value.  If signature is not empty, it is
  // validated by securifier or default_securifer.
  void Store(const Key &key,
             const std::string &value,
             const std::string &signature,
             const boost::posix_time::time_duration &ttl,
             PrivateKeyPtr private_key,
             StoreFunctor callback);

  // Delete <key,value,signature> from network.  If signature is empty, the
  // value is signed using securifier, unless it is invalid, in which case
  // the node's default_securifier signs value.  If signature is not empty, it
  // is validated by securifier or default_securifer.  The securifier must sign
  // and encrypt with the same cryptographic keys as were used when the
  // <key,value,signature> was stored.
  void Delete(const Key &key,
              const std::string &value,
              const std::string &signature,
              PrivateKeyPtr private_key,
              DeleteFunctor callback);

  // Replace <key,old_value,old_signature> with <key,new_value,new_signature>
  // on the network.  If either signature is empty, the corresponding value is
  // signed using securifier, unless it is invalid, in which case the node's
  // default_securifier signs the value.  If a signature is not empty, it is
  // validated by securifier or default_securifer.  The securifier must sign
  // and encrypt with the same cryptographic keys as were used when the
  // <key,old_value,old_signature> was stored.  Infinite ttl is indicated by
  // boost::posix_time::pos_infin.
  void Update(const Key &key,
              const std::string &new_value,
              const std::string &new_signature,
              const std::string &old_value,
              const std::string &old_signature,
              const boost::posix_time::time_duration &ttl,
              PrivateKeyPtr private_key,
              UpdateFunctor callback);

  // Find value(s) on the network.  The callback will always have passed to it
  // the contact details of the node needing a cache copy of the value(s) (i.e.
  // the last node during the search to not hold the value(s)).  This could be
  // an empty contact (e.g. if the lookup failed, or was completed by the first
  // RPC's callback).  If cache is true for this lookup, the cache contact is
  // not empty, and the value(s) are found, then the cache contact is sent the
  // value(s) for caching.
  //
  // Other than this, the callback parameters are populated as follows:
  // * If any queried peer holds the value(s) outwith its kademlia datastore
  //   (indicated by a positive result from invoking the check_cache_functor
  //   which has a setter below), its details are passed in the callback and no
  //   other callback parameters are completed.  In this case, the return code
  //   is kFoundCachedCopyHolder.
  // * If any queried peer holds the value(s) in its kademlia datastore, the
  //   value(s) and signature(s) are passed in the callback and no other
  //   callback parameters are completed.  In this case, the return code is
  //   kSuccess.
  // * Otherwise, iff no value exists under key, the (k + extra) closest nodes'
  //   details are passed in callback, ordered by kademlia closeness to key,
  //   closest first.  In this case, the return code is kFailedToFindValue.
  //
  // These return codes are all >= 0.  Any other return code indicates an error
  // in the lookup process and will be < 0.  N.B. This node could be returned as
  // the cached_copy_holder or as one of the closest contacts.
  void FindValue(const Key &key,
                 PrivateKeyPtr private_key,
                 FindValueFunctor callback,
                 const uint16_t &extra_contacts = 0,
                 bool cache = true);

  // Find details of (k + extra) nodes closest to key.  The details are passed
  // in callback, ordered by kademlia closeness to key, closest first.
  // N.B. This node could be returned as one of the closest contacts.
  void FindNodes(const Key &key,
                 FindNodesFunctor callback,
                 const uint16_t &extra_contacts = 0);

  // Find the contact details of a node.  If the target node is not in this
  // node's routing table (and is not this node), a FindNode will be executed.
  // If the node is offline, a default-constructed Contact will be passed back
  // in the callback.
  void GetContact(const NodeId &node_id, GetContactFunctor callback);

  // Setter for the functor which will be called by Node and Service to retrieve
  // the public key and public key validation token for a given contact.
  void SetContactValidationGetter(
      asymm::GetPublicKeyAndValidationFunctor contact_validation_getter);

  // Setter for the functor which will be invoked in the callback of
  // contact_validation_getter above.  It will return true if the retrieved
  // public key validates correctly against the retrieved validation token.
  void SetContactValidator(asymm::ValidatePublicKeyFunctor contact_validator);

  // Setter for the functor which will be invoked for checking a signature
  // against a given public key.
  void SetValidate(asymm::ValidateFunctor validate_functor);

  // Mark contact in routing table as having just been seen (i.e. contacted).
  void SetLastSeenToNow(const Contact &contact);

  // Mark contact in routing table as having failed to respond correctly to an
  // RPC request.
  void IncrementFailedRpcs(const Contact &contact);

  // Update contact in routing table with revised rank info.
  void UpdateRankInfo(const Contact &contact, RankInfoPtr rank_info);

  // Retrieve rank info from contact in routing table.  No network operation is
  // executed.
  RankInfoPtr GetLocalRankInfo(const Contact &contact);

  // Retrieve all contacts from the routing table.  No network operation is
  // executed.
  void GetAllContacts(std::vector<Contact> *contacts);

  // Retrieve all directly-connected contacts from the routing table.  No
  // network operation is executed.
  void GetBootstrapContacts(std::vector<Contact> *contacts);

  // Checks whether the contact is online or not
  void Ping(const Contact &contact, PingFunctor callback);

  // Sets a functor which is invoked whenever this node's Service receives a
  // FindValue RPC.  If the functor returns true, the node responds that it has
  // a copy of the requested value (somewhere other than its internal
  // DataStore), and hence causes the peer's lookup to terminate.
  void set_check_cache_functor(const CheckCacheFunctor &check_cache_functor);

  // This node's contact details
  Contact contact() const;

  // Whether node is currently joined to the network.
  bool joined() const;

  // Getters
  OnOnlineStatusChangePtr on_online_status_change();
  bool client_only_node() const;
  uint16_t k() const;

 private:
  std::unique_ptr<NodeImpl> pimpl_;
};


struct FindValueReturns {
  FindValueReturns() : return_code(kPendingResult),
                       values_and_signatures(),
                       closest_nodes(),
                       cached_copy_holder(),
                       needs_cache_copy() {}
  FindValueReturns(
      int return_code_in,
      const std::vector<ValueAndSignature> &values_and_signatures_in,
      const std::vector<Contact> &closest_nodes_in,
      const Contact &cached_copy_holder_in,
      const Contact &needs_cache_copy_in)
          : return_code(return_code_in),
            values_and_signatures(values_and_signatures_in),
            closest_nodes(closest_nodes_in),
            cached_copy_holder(cached_copy_holder_in),
            needs_cache_copy(needs_cache_copy_in) {}
  int return_code;
  std::vector<ValueAndSignature> values_and_signatures;
  std::vector<Contact> closest_nodes;
  Contact cached_copy_holder;
  Contact needs_cache_copy;
};

}  // namespace dht

}  // namespace maidsafe

#endif  // MAIDSAFE_DHT_NODE_API_H_

Added wiki_references/2017/software/MaidSafe_net/src_from_GitHub/the_repository_clones/MaidSafe-DHT/src/maidsafe/dht/node.cc version [1bbc201a05].



































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
/* Copyright (c) 2009 maidsafe.net limited
All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

    * Redistributions of source code must retain the above copyright notice,
    this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright notice,
    this list of conditions and the following disclaimer in the documentation
    and/or other materials provided with the distribution.
    * Neither the name of the maidsafe.net limited nor the names of its
    contributors may be used to endorse or promote products derived from this
    software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include "maidsafe/dht/node-api.h"
#include "maidsafe/dht/node_impl.h"
#include "maidsafe/dht/contact.h"

namespace maidsafe {

namespace dht {

Node::Node(boost::asio::io_service &asio_service,             // NOLINT (Fraser)
           TransportPtr listening_transport,
           MessageHandlerPtr message_handler,
           KeyPairPtr default_key_pair,
           bool client_only_node,
           const uint16_t &k,
           const uint16_t &alpha,
           const uint16_t &beta,
           const boost::posix_time::time_duration &mean_refresh_interval)
    : pimpl_(new NodeImpl(asio_service, listening_transport, message_handler,
                          default_key_pair, client_only_node, k, alpha, beta,
                          mean_refresh_interval)) {}

Node::~Node() {}

void Node::Join(const NodeId &node_id,
                std::vector<Contact> bootstrap_contacts,
                JoinFunctor callback) {
  pimpl_->Join(node_id, bootstrap_contacts, callback);
}

void Node::Leave(std::vector<Contact> *bootstrap_contacts) {
  pimpl_->Leave(bootstrap_contacts);
}

void Node::Store(const Key &key,
                 const std::string &value,
                 const std::string &signature,
                 const boost::posix_time::time_duration &ttl,
                 PrivateKeyPtr private_key,
                 StoreFunctor callback) {
  pimpl_->Store(key, value, signature, ttl, private_key, callback);
}

void Node::Delete(const Key &key,
                 const std::string &value,
                 const std::string &signature,
                 PrivateKeyPtr private_key,
                 DeleteFunctor callback) {
  pimpl_->Delete(key, value, signature, private_key, callback);
}

void Node::Update(const Key &key,
                  const std::string &new_value,
                  const std::string &new_signature,
                  const std::string &old_value,
                  const std::string &old_signature,
                  const boost::posix_time::time_duration &ttl,
                  PrivateKeyPtr private_key,
                  UpdateFunctor callback) {
  pimpl_->Update(key, new_value, new_signature, old_value, old_signature,
                 ttl, private_key, callback);
}

void Node::FindValue(const Key &key,
                     PrivateKeyPtr private_key,
                     FindValueFunctor callback,
                     const uint16_t &extra_contacts,
                     bool cache) {
  pimpl_->FindValue(key, private_key, callback, extra_contacts, cache);
}

void Node::FindNodes(const Key &key,
                     FindNodesFunctor callback,
                     const uint16_t &extra_contacts) {
  pimpl_->FindNodes(key, callback, extra_contacts);
}

void Node::GetContact(const NodeId &node_id, GetContactFunctor callback) {
  pimpl_->GetContact(node_id, callback);
}

void Node::SetContactValidationGetter(
    asymm::GetPublicKeyAndValidationFunctor contact_validation_getter) {
  pimpl_->SetContactValidationGetter(contact_validation_getter);
}

void Node::SetContactValidator(
    asymm::ValidatePublicKeyFunctor contact_validator) {
  pimpl_->SetContactValidator(contact_validator);
}

void Node::SetValidate(asymm::ValidateFunctor validate_functor) {
  pimpl_->SetValidate(validate_functor);
}

void Node::SetLastSeenToNow(const Contact &contact) {
  pimpl_->SetLastSeenToNow(contact);
}

void Node::IncrementFailedRpcs(const Contact &contact) {
  pimpl_->IncrementFailedRpcs(contact);
}

void Node::UpdateRankInfo(const Contact &contact, RankInfoPtr rank_info) {
  pimpl_->UpdateRankInfo(contact, rank_info);
}

RankInfoPtr Node::GetLocalRankInfo(const Contact &contact) {
  return pimpl_->GetLocalRankInfo(contact);
}

void Node::GetAllContacts(std::vector<Contact> *contacts) {
  pimpl_->GetAllContacts(contacts);
}

void Node::GetBootstrapContacts(std::vector<Contact> *contacts) {
  pimpl_->GetBootstrapContacts(contacts);
}

void Node::Ping(const Contact &contact, PingFunctor callback) {
  pimpl_->Ping(contact, callback);
}

void Node::set_check_cache_functor(
    const CheckCacheFunctor &check_cache_functor) {
  pimpl_->set_check_cache_functor(check_cache_functor);
}

Contact Node::contact() const {
  return pimpl_->contact();
}

bool Node::joined() const {
  return pimpl_->joined();
}

OnOnlineStatusChangePtr Node::on_online_status_change() {
  return pimpl_->on_online_status_change();
}

bool Node::client_only_node() const {
  return pimpl_->client_only_node();
}

uint16_t Node::k() const {
  return pimpl_->k();
}

}  // namespace dht

}  // namespace maidsafe

Added wiki_references/2017/software/MaidSafe_net/src_from_GitHub/the_repository_clones/MaidSafe-DHT/src/maidsafe/dht/node_container.h version [4b0a015924].











































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
/* Copyright (c) 2011 maidsafe.net limited
All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

    * Redistributions of source code must retain the above copyright notice,
    this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright notice,
    this list of conditions and the following disclaimer in the documentation
    and/or other materials provided with the distribution.
    * Neither the name of the maidsafe.net limited nor the names of its
    contributors may be used to endorse or promote products derived from this
    software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/


#ifndef MAIDSAFE_DHT_NODE_CONTAINER_H_
#define MAIDSAFE_DHT_NODE_CONTAINER_H_

#include <memory>
#include <string>
#include <utility>
#include <vector>

#include "boost/asio/io_service.hpp"
#include "boost/date_time/posix_time/posix_time_duration.hpp"
#include "boost/thread.hpp"

#include "maidsafe/common/asio_service.h"
#include "maidsafe/common/crypto.h"

#include "maidsafe/transport/rudp_transport.h"
#include "maidsafe/transport/tcp_transport.h"
#include "maidsafe/transport/udp_transport.h"
// TODO(Fraser#5#): 2011-08-30 - remove #include utils.h once NAT detection is
//                  implemented.
#include "maidsafe/transport/utils.h"

#include "maidsafe/dht/config.h"
#include "maidsafe/dht/message_handler.h"
#include "maidsafe/dht/version.h"
#include "maidsafe/dht/node-api.h"
#include "maidsafe/dht/return_codes.h"

#if MAIDSAFE_DHT_VERSION != 3200
#  error This API is not compatible with the installed library.\
    Please update the maidsafe-dht library.
#endif

namespace args = std::placeholders;
namespace bptime = boost::posix_time;

namespace maidsafe {

namespace dht {

template <typename NodeType>
class NodeContainer {
 public:
  NodeContainer();
  virtual ~NodeContainer();

  virtual void Init(
      uint8_t thread_count,
      KeyPairPtr key_pair,
      MessageHandlerPtr message_handler,
      bool client_only_node,
      uint16_t k = 8,
      uint16_t alpha = 3,
      uint16_t beta = 2,
      bptime::time_duration mean_refresh_interval = bptime::hours(1));

  // For a non-client, starts listening on a random port within the range.  Then
  // for all types, joins network.
  int Start(const std::vector<Contact> &bootstrap_contacts,
            std::pair<uint16_t, uint16_t> port_range);
  // Joins the network. Only for a client only nodes.
  int StartClient(const std::vector<Contact> &bootstrap_contacts);

  // Stops listening (if non-client) and leaves network.  Joins all threads.
  int Stop(std::vector<Contact> *bootstrap_contacts);

  // These 8 functions call the corresponding function on node_ using the
  // corresponding member callback functors of this class.
  void Join(const NodeId &node_id,
            const std::vector<Contact> &bootstrap_contacts);
  void Store(const Key &key,
             const std::string &value,
             const std::string &signature,
             const boost::posix_time::time_duration &ttl,
             PrivateKeyPtr private_key);
  void Delete(const Key &key,
              const std::string &value,
              const std::string &signature,
              PrivateKeyPtr private_key);
  void Update(const Key &key,
              const std::string &new_value,
              const std::string &new_signature,
              const std::string &old_value,
              const std::string &old_signature,
              const boost::posix_time::time_duration &ttl,
              PrivateKeyPtr private_key);
  void FindValue(const Key &key,
                 PrivateKeyPtr private_key,
                 const uint16_t &extra_contacts = 0);
  void FindNodes(const Key &key,
                 const uint16_t &extra_contacts = 0);
  void GetContact(const NodeId &node_id);
  void Ping(const Contact &contact);

  // These Make<XXX>Functor functions set the appropriate <XXX>_functor_ by
  // binding the corresponding private <XXX>Callback method.
  void MakeJoinFunctor(boost::mutex *mutex,
                       boost::condition_variable *cond_var);
  void MakeStoreFunctor(boost::mutex *mutex,
                        boost::condition_variable *cond_var);
  void MakeDeleteFunctor(boost::mutex *mutex,
                         boost::condition_variable *cond_var);
  void MakeUpdateFunctor(boost::mutex *mutex,
                         boost::condition_variable *cond_var);
  void MakeFindValueFunctor(boost::mutex *mutex,
                            boost::condition_variable *cond_var);
  void MakeFindNodesFunctor(boost::mutex *mutex,
                            boost::condition_variable *cond_var);
  void MakeGetContactFunctor(boost::mutex *mutex,
                             boost::condition_variable *cond_var);
  void MakePingFunctor(boost::mutex *mutex,
                       boost::condition_variable *cond_var);
  // Convenience method for where all callback functors use the same mutex and
  // cond_var
  void MakeAllCallbackFunctors(boost::mutex *mutex,
                               boost::condition_variable *cond_var);

  // These 7 setters allow using a different callback method to the one provided
  // in this class.
  void set_join_functor(const JoinFunctor &functor) {
    join_functor_ = functor;
  }
  void set_store_functor(const StoreFunctor &functor) {
    store_functor_ = functor;
  }
  void set_delete_functor(const DeleteFunctor &functor) {
    delete_functor_ = functor;
  }
  void set_update_functor(const UpdateFunctor &functor) {
    update_functor_ = functor;
  }
  void set_find_value_functor(const FindValueFunctor &functor) {
    find_value_functor_ = functor;
  }
  void set_find_nodes_functor(const FindNodesFunctor &functor) {
    find_nodes_functor_ = functor;
  }
  void set_get_contact_functor(const GetContactFunctor &functor) {
    get_contact_functor_ = functor;
  }
  void set_ping_functor(const PingFunctor &functor) {
    ping_functor_ = functor;
  }

  // These 7 getters also set corresponding class member results to
  // kPendingResult and clear any corresponding result structs/containers ready
  // for subsequent calls.
  void GetAndResetJoinResult(int *result);
  void GetAndResetStoreResult(int *result);
  void GetAndResetDeleteResult(int *result);
  void GetAndResetUpdateResult(int *result);
  void GetAndResetFindNodesResult(int *result,
                                  std::vector<Contact> *closest_nodes);
  void GetAndResetFindValueResult(FindValueReturns *find_value_returns);
  void GetAndResetGetContactResult(int *result, Contact *contact);
  void GetAndResetPingResult(int *result);

  // This returns the io_service by reference!  This is needed by almost any
  // asio object which takes an io_service in its constructor.  Ensure that if
  // this getter is used, this class instance outlives the caller.
  boost::asio::io_service &asio_service() { return asio_service_.service(); }

  // Standard getters
  std::shared_ptr<NodeType> node() const { return node_; }
  KeyPairPtr key_pair() const { return key_pair_; }
  std::vector<Contact> bootstrap_contacts() const {
    return bootstrap_contacts_;
  }
  JoinFunctor join_functor() const { return join_functor_; }
  StoreFunctor store_functor() const { return store_functor_; }
  DeleteFunctor delete_functor() const { return delete_functor_; }
  UpdateFunctor update_functor() const { return update_functor_; }
  FindValueFunctor find_value_functor() const { return find_value_functor_; }
  FindNodesFunctor find_nodes_functor() const { return find_nodes_functor_; }
  GetContactFunctor get_contact_functor() const { return get_contact_functor_; }
  PingFunctor ping_functor() const { return ping_functor_; }

  // These WaitFunctors can be used inside boost wait or timed_wait functions
  // as predicates.
  WaitFunctor wait_for_join_functor() const { return wait_for_join_functor_; }
  WaitFunctor wait_for_store_functor() const { return wait_for_store_functor_; }
  WaitFunctor wait_for_delete_functor() const {
    return wait_for_delete_functor_;
  }
  WaitFunctor wait_for_update_functor() const {
    return wait_for_update_functor_;
  }
  WaitFunctor wait_for_find_value_functor() const {
    return wait_for_find_value_functor_;
  }
  WaitFunctor wait_for_find_nodes_functor() const {
    return wait_for_find_nodes_functor_;
  }
  WaitFunctor wait_for_get_contact_functor() const {
    return wait_for_get_contact_functor_;
  }
  WaitFunctor wait_for_ping_functor() const { return wait_for_ping_functor_; }


 protected:
  AsioService asio_service_;
  TransportPtr listening_transport_;
  MessageHandlerPtr message_handler_;
  KeyPairPtr key_pair_;
  std::shared_ptr<NodeType> node_;
  std::vector<Contact> bootstrap_contacts_;
  int join_result_, store_result_, delete_result_, update_result_,
      find_nodes_result_, get_contact_result_, ping_result_;
  FindValueReturns find_value_returns_;
  std::vector<Contact> find_nodes_closest_nodes_;
  Contact gotten_contact_;
  WaitFunctor wait_for_join_functor_;
  WaitFunctor wait_for_store_functor_;
  WaitFunctor wait_for_delete_functor_;
  WaitFunctor wait_for_update_functor_;
  WaitFunctor wait_for_find_value_functor_;
  WaitFunctor wait_for_find_nodes_functor_;
  WaitFunctor wait_for_get_contact_functor_;
  WaitFunctor wait_for_ping_functor_;

 private:
  NodeContainer(const NodeContainer&);
  NodeContainer &operator=(const NodeContainer&);
  void JoinCallback(int result_in,
                    boost::mutex *mutex,
                    boost::condition_variable *cond_var);
  void StoreCallback(int result_in,
                     boost::mutex *mutex,
                     boost::condition_variable *cond_var);
  void DeleteCallback(int result_in,
                      boost::mutex *mutex,
                      boost::condition_variable *cond_var);
  void UpdateCallback(int result_in,
                      boost::mutex *mutex,
                      boost::condition_variable *cond_var);
  void FindValueCallback(FindValueReturns find_value_returns_in,
                         boost::mutex *mutex,
                         boost::condition_variable *cond_var);
  void FindNodesCallback(int result_in,
                         std::vector<Contact> closest_nodes_in,
                         boost::mutex *mutex,
                         boost::condition_variable *cond_var);
  void GetContactCallback(int result_in,
                          Contact contact_in,
                          boost::mutex *mutex,
                          boost::condition_variable *cond_var);
  void PingCallback(int result_in,
                    boost::mutex *mutex,
                    boost::condition_variable *cond_var);
  bool ResultReady(int *result) { return *result != kPendingResult; }
  JoinFunctor join_functor_;
  StoreFunctor store_functor_;
  DeleteFunctor delete_functor_;
  UpdateFunctor update_functor_;
  FindValueFunctor find_value_functor_;
  FindNodesFunctor find_nodes_functor_;
  GetContactFunctor get_contact_functor_;
  PingFunctor ping_functor_;
};

template <typename NodeType>
std::string DebugId(const NodeContainer<NodeType> &container) {
  return maidsafe::dht::DebugId(container.node()->contact());
}


template<typename NodeType>
NodeContainer<NodeType>::NodeContainer()
    : asio_service_(),
      listening_transport_(),
      message_handler_(),
      key_pair_(),
      node_(),
      bootstrap_contacts_(),
      join_result_(kPendingResult),
      store_result_(kPendingResult),
      delete_result_(kPendingResult),
      update_result_(kPendingResult),
      find_nodes_result_(kPendingResult),
      get_contact_result_(kPendingResult),
      ping_result_(kPendingResult),
      find_value_returns_(),
      find_nodes_closest_nodes_(),
      gotten_contact_(),
      wait_for_join_functor_(),
      wait_for_store_functor_(),
      wait_for_delete_functor_(),
      wait_for_update_functor_(),
      wait_for_find_value_functor_(),
      wait_for_find_nodes_functor_(),
      wait_for_get_contact_functor_(),
      wait_for_ping_functor_(),
      join_functor_(),
      store_functor_(),
      delete_functor_(),
      update_functor_(),
      find_value_functor_(),
      find_nodes_functor_(),
      get_contact_functor_(),
      ping_functor_() {
  wait_for_join_functor_ =
      std::bind(&NodeContainer<NodeType>::ResultReady, this, &join_result_);
  wait_for_store_functor_ =
      std::bind(&NodeContainer<NodeType>::ResultReady, this, &store_result_);
  wait_for_delete_functor_ =
      std::bind(&NodeContainer<NodeType>::ResultReady, this, &delete_result_);
  wait_for_update_functor_ =
      std::bind(&NodeContainer<NodeType>::ResultReady, this, &update_result_);
  wait_for_find_value_functor_ =
      std::bind(&NodeContainer<NodeType>::ResultReady, this,
                &find_value_returns_.return_code);
  wait_for_find_nodes_functor_ =
      std::bind(&NodeContainer<NodeType>::ResultReady, this,
                &find_nodes_result_);
  wait_for_get_contact_functor_ =
      std::bind(&NodeContainer<NodeType>::ResultReady, this,
                &get_contact_result_);
  wait_for_ping_functor_ =
      std::bind(&NodeContainer<NodeType>::ResultReady, this, &ping_result_);
}

template<typename NodeType>
NodeContainer<NodeType>::~NodeContainer() {
  Stop(nullptr);
}

template <typename NodeType>
void NodeContainer<NodeType>::Init(
    uint8_t thread_count,
    KeyPairPtr key_pair,
    MessageHandlerPtr message_handler,
    bool client_only_node,
    uint16_t k,
    uint16_t alpha,
    uint16_t beta,
    bptime::time_duration mean_refresh_interval) {
  // Create worker threads for asynchronous operations.
  asio_service_.Start(thread_count);

  // Set up private_key if it wasn't passed in - make signing_key_id compatible
  // with type NodeId so that the node's ID can be set as the public key's ID
  if (key_pair) {
    key_pair_ = key_pair;
  } else {
    key_pair_ = KeyPairPtr(new asymm::Keys);
    asymm::GenerateKeyPair(key_pair_.get());
    key_pair_->identity = RandomString(crypto::SHA512::DIGESTSIZE);
  }

  if (message_handler) {
    message_handler_ = message_handler;
  } else {
    PrivateKeyPtr priv_key = PrivateKeyPtr(
        new asymm::PrivateKey(key_pair_->private_key));
    message_handler_.reset(new MessageHandler(priv_key));
  }

  // If this is not a client node, connect message handler to transport for
  // incoming raw messages.  Don't need to connect to on_error() as service
  // doesn't care if reply succeeds or not.
  if (!client_only_node) {
//    listening_transport_.reset(
//        new transport::TcpTransport(asio_service_.service()));
    listening_transport_.reset(
        new transport::TcpTransport(asio_service_.service()));
    listening_transport_->on_message_received()->connect(
        transport::OnMessageReceived::element_type::slot_type(
            &MessageHandler::OnMessageReceived, message_handler_.get(),
            _1, _2, _3, _4).track_foreign(message_handler_));
    listening_transport_->on_error()->connect(
        transport::OnError::element_type::slot_type(
            &MessageHandler::OnError, message_handler_.get(),
            _1, _2).track_foreign(message_handler));
  }

  // Create node
  node_.reset(new NodeType(asio_service_.service(), listening_transport_,
                           message_handler_, key_pair_, client_only_node, k,
                           alpha, beta, mean_refresh_interval));
}

template <typename NodeType>
int NodeContainer<NodeType>::Start(
    const std::vector<dht::Contact> &bootstrap_contacts,
    std::pair<uint16_t, uint16_t> port_range) {
  bootstrap_contacts_ = bootstrap_contacts;
  int result(kPendingResult);
  if (!node_->client_only_node()) {
     // Workaround until NAT detection is up.
    std::vector<transport::IP> ips = transport::GetLocalAddresses();
    transport::Endpoint endpoint(
        ips.empty() ? IP::from_string("127.0.0.1") : ips.front(), 0);
    int result(transport::kError);
    std::vector<Port> try_ports;
    if (port_range.first == port_range.second) {
      try_ports.reserve(1);
      try_ports.push_back(port_range.first);
    } else  {
      if (port_range.first > port_range.second)
        port_range = std::make_pair(port_range.second, port_range.first);
      try_ports.reserve(port_range.second - port_range.first);
      for (Port port(port_range.first); port != port_range.second; ++port)
        try_ports.push_back(port);
      std::random_shuffle(try_ports.begin(), try_ports.end());
    }
    for (auto itr(try_ports.begin()); itr != try_ports.end(); ++itr) {
      endpoint.port = *itr;
      result = listening_transport_->StartListening(endpoint);
      if (transport::kSuccess == result) {
        break;
      } else {
        listening_transport_->StopListening();
      }
    }
    if (transport::kSuccess != result) {
      return result;
    }
  }

  boost::mutex mutex;
  boost::condition_variable cond_var;
  NodeId node_id(key_pair_->identity);
  JoinFunctor join_functor(std::bind(&NodeContainer<NodeType>::JoinCallback,
                           this, args::_1, &mutex, &cond_var));

  boost::function<bool()> wait_functor = boost::bind(
      &NodeContainer<NodeType>::ResultReady, this, &join_result_);
  boost::mutex::scoped_lock lock(mutex);
  node_->Join(node_id, bootstrap_contacts_, join_functor);
  bool wait_success(cond_var.timed_wait(lock, bptime::minutes(1),
                                        wait_functor));
  result = kPendingResult;
  GetAndResetJoinResult(&result);
  return (wait_success ? result : kTimedOut);
}

template <typename NodeType>
int NodeContainer<NodeType>::StartClient(
    const std::vector<dht::Contact> &bootstrap_contacts) {
  if (node_->client_only_node()) {
    std::pair<Port, Port> port_range(0, 0);
    return Start(bootstrap_contacts, port_range);
  }
  return kGeneralError;
}

template <typename NodeType>
int NodeContainer<NodeType>::Stop(std::vector<Contact> *bootstrap_contacts) {
  try {
    if (node_->joined()) {
      node_->Leave(&bootstrap_contacts_);
      if (bootstrap_contacts)
        *bootstrap_contacts = bootstrap_contacts_;
    }
  } catch(const std::exception&) {
    return kGeneralError;
  }
  if (listening_transport_)
    listening_transport_->StopListening();
  asio_service_.Stop();
  return kSuccess;
}

template <typename NodeType>
void NodeContainer<NodeType>::Join(
    const NodeId &node_id,
    const std::vector<Contact> &bootstrap_contacts) {
  node_->Join(node_id, bootstrap_contacts, join_functor_);
}

template <typename NodeType>
void NodeContainer<NodeType>::Store(const Key &key,
                                    const std::string &value,
                                    const std::string &signature,
                                    const boost::posix_time::time_duration &ttl,
                                    PrivateKeyPtr private_key) {
  node_->Store(key, value, signature, ttl, private_key, store_functor_);
}

template <typename NodeType>
void NodeContainer<NodeType>::Delete(const Key &key,
                                     const std::string &value,
                                     const std::string &signature,
                                     PrivateKeyPtr private_key) {
  node_->Delete(key, value, signature, private_key, delete_functor_);
}

template <typename NodeType>
void NodeContainer<NodeType>::Update(
    const Key &key,
    const std::string &new_value,
    const std::string &new_signature,
    const std::string &old_value,
    const std::string &old_signature,
    const boost::posix_time::time_duration &ttl,
    PrivateKeyPtr private_key) {
  node_->Update(key, new_value, new_signature, old_value, old_signature, ttl,
                private_key, update_functor_);
}

template <typename NodeType>
void NodeContainer<NodeType>::FindValue(const Key &key,
                                        PrivateKeyPtr private_key,
                                        const uint16_t &extra_contacts) {
  node_->FindValue(key, private_key, find_value_functor_, extra_contacts);
}

template <typename NodeType>
void NodeContainer<NodeType>::FindNodes(const Key &key,
                                        const uint16_t &extra_contacts) {
  node_->FindNodes(key, find_nodes_functor_, extra_contacts);
}

template <typename NodeType>
void NodeContainer<NodeType>::GetContact(const NodeId &node_id) {
  node_->GetContact(node_id, get_contact_functor_);
}

template <typename NodeType>
void NodeContainer<NodeType>::Ping(const Contact &contact) {
  node_->Ping(contact, ping_functor_);
}

template <typename NodeType>
void NodeContainer<NodeType>::JoinCallback(
    int result_in,
    boost::mutex *mutex,
    boost::condition_variable *cond_var) {
  boost::mutex::scoped_lock lock(*mutex);
  join_result_ = result_in;
  cond_var->notify_one();
}

template <typename NodeType>
void NodeContainer<NodeType>::StoreCallback(
    int result_in,
    boost::mutex *mutex,
    boost::condition_variable *cond_var) {
  boost::mutex::scoped_lock lock(*mutex);
  store_result_ = result_in;
  cond_var->notify_one();
}

template <typename NodeType>
void NodeContainer<NodeType>::DeleteCallback(
    int result_in,
    boost::mutex *mutex,
    boost::condition_variable *cond_var) {
  boost::mutex::scoped_lock lock(*mutex);
  delete_result_ = result_in;
  cond_var->notify_one();
}

template <typename NodeType>
void NodeContainer<NodeType>::UpdateCallback(
    int result_in,
    boost::mutex *mutex,
    boost::condition_variable *cond_var) {
  boost::mutex::scoped_lock lock(*mutex);
  update_result_ = result_in;
  cond_var->notify_one();
}

template <typename NodeType>
void NodeContainer<NodeType>::FindValueCallback(
    FindValueReturns find_value_returns_in,
    boost::mutex *mutex,
    boost::condition_variable *cond_var) {
  boost::mutex::scoped_lock lock(*mutex);
  find_value_returns_ = find_value_returns_in;
  cond_var->notify_one();
}

template <typename NodeType>
void NodeContainer<NodeType>::FindNodesCallback(
    int result_in,
    std::vector<Contact> closest_nodes_in,
    boost::mutex *mutex,
    boost::condition_variable *cond_var) {
  boost::mutex::scoped_lock lock(*mutex);
  find_nodes_result_ = result_in;
  find_nodes_closest_nodes_ = closest_nodes_in;
  cond_var->notify_one();
}

template <typename NodeType>
void NodeContainer<NodeType>::GetContactCallback(
    int result_in,
    Contact contact_in,
    boost::mutex *mutex,
    boost::condition_variable *cond_var) {
  boost::mutex::scoped_lock lock(*mutex);
  get_contact_result_ = result_in;
  gotten_contact_ = contact_in;
  cond_var->notify_one();
}

template <typename NodeType>
void NodeContainer<NodeType>::PingCallback(
    int result_in,
    boost::mutex *mutex,
    boost::condition_variable *cond_var) {
  boost::mutex::scoped_lock lock(*mutex);
  ping_result_ = result_in;
  cond_var->notify_one();
}

template <typename NodeType>
void NodeContainer<NodeType>::MakeJoinFunctor(
    boost::mutex *mutex,
    boost::condition_variable *cond_var) {
  join_functor_ = std::bind(&NodeContainer<NodeType>::JoinCallback, this,
                            args::_1, mutex, cond_var);
}

template <typename NodeType>
void NodeContainer<NodeType>::MakeStoreFunctor(
    boost::mutex *mutex,
    boost::condition_variable *cond_var) {
  store_functor_ = std::bind(&NodeContainer<NodeType>::StoreCallback, this,
                             args::_1, mutex, cond_var);
}

template <typename NodeType>
void NodeContainer<NodeType>::MakeDeleteFunctor(
    boost::mutex *mutex,
    boost::condition_variable *cond_var) {
  delete_functor_ = std::bind(&NodeContainer<NodeType>::DeleteCallback, this,
                              args::_1, mutex, cond_var);
}

template <typename NodeType>
void NodeContainer<NodeType>::MakeUpdateFunctor(
    boost::mutex *mutex,
    boost::condition_variable *cond_var) {
  update_functor_ = std::bind(&NodeContainer<NodeType>::UpdateCallback, this,
                              args::_1, mutex, cond_var);
}

template <typename NodeType>
void NodeContainer<NodeType>::MakeFindValueFunctor(
    boost::mutex *mutex,
    boost::condition_variable *cond_var) {
  find_value_functor_ = std::bind(&NodeContainer<NodeType>::FindValueCallback,
                                  this, args::_1, mutex, cond_var);
}

template <typename NodeType>
void NodeContainer<NodeType>::MakeFindNodesFunctor(
    boost::mutex *mutex,
    boost::condition_variable *cond_var) {
  find_nodes_functor_ = std::bind(&NodeContainer<NodeType>::FindNodesCallback,
                                  this, args::_1, args::_2, mutex, cond_var);
}

template <typename NodeType>
void NodeContainer<NodeType>::MakeGetContactFunctor(
    boost::mutex *mutex,
    boost::condition_variable *cond_var) {
  get_contact_functor_ = std::bind(&NodeContainer<NodeType>::GetContactCallback,
                                   this, args::_1, args::_2, mutex, cond_var);
}

template <typename NodeType>
void NodeContainer<NodeType>::MakePingFunctor(
    boost::mutex *mutex,
    boost::condition_variable *cond_var) {
  ping_functor_ = std::bind(&NodeContainer<NodeType>::PingCallback, this,
                            args::_1, mutex, cond_var);
}

template <typename NodeType>
void NodeContainer<NodeType>::MakeAllCallbackFunctors(
    boost::mutex *mutex,
    boost::condition_variable *cond_var) {
  MakeJoinFunctor(mutex, cond_var);
  MakeStoreFunctor(mutex, cond_var);
  MakeDeleteFunctor(mutex, cond_var);
  MakeUpdateFunctor(mutex, cond_var);
  MakeFindValueFunctor(mutex, cond_var);
  MakeFindNodesFunctor(mutex, cond_var);
  MakeGetContactFunctor(mutex, cond_var);
  MakePingFunctor(mutex, cond_var);
}


template <typename NodeType>
void NodeContainer<NodeType>::GetAndResetJoinResult(int *result) {
  if (result)
    *result = join_result_;
  join_result_ = kPendingResult;
}

template <typename NodeType>
void NodeContainer<NodeType>::GetAndResetStoreResult(int *result) {
  if (result)
    *result = store_result_;
  store_result_ = kPendingResult;
}

template <typename NodeType>
void NodeContainer<NodeType>::GetAndResetDeleteResult(int *result) {
  if (result)
    *result = delete_result_;
  delete_result_ = kPendingResult;
}

template <typename NodeType>
void NodeContainer<NodeType>::GetAndResetUpdateResult(int *result) {
  if (result)
    *result = update_result_;
  update_result_ = kPendingResult;
}

template <typename NodeType>
void NodeContainer<NodeType>::GetAndResetFindNodesResult(
    int *result,
    std::vector<Contact> *closest_nodes) {
  if (result)
    *result = find_nodes_result_;
  if (closest_nodes)
    *closest_nodes = find_nodes_closest_nodes_;
  find_nodes_result_ = kPendingResult;
  find_nodes_closest_nodes_.clear();
}

template <typename NodeType>
void NodeContainer<NodeType>::GetAndResetFindValueResult(
    FindValueReturns *find_value_returns) {
  if (find_value_returns)
    *find_value_returns = find_value_returns_;
  find_value_returns_.cached_copy_holder = Contact();
  find_value_returns_.closest_nodes.clear();
  find_value_returns_.needs_cache_copy = Contact();
  find_value_returns_.return_code = kPendingResult;
  find_value_returns_.values_and_signatures.clear();
}

template <typename NodeType>
void NodeContainer<NodeType>::GetAndResetGetContactResult(int *result,
                                                          Contact *contact) {
  if (result)
    *result = get_contact_result_;
  if (contact)
    *contact = gotten_contact_;
  get_contact_result_ = kPendingResult;
  gotten_contact_ = Contact();
}

template <typename NodeType>
void NodeContainer<NodeType>::GetAndResetPingResult(int *result) {
  if (result)
    *result = ping_result_;
  ping_result_ = kPendingResult;
}

}  // namespace dht

}  // namespace maidsafe

#endif  // MAIDSAFE_DHT_NODE_CONTAINER_H_

Added wiki_references/2017/software/MaidSafe_net/src_from_GitHub/the_repository_clones/MaidSafe-DHT/src/maidsafe/dht/node_id.cc version [56a4e7e538].

























































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
/* Copyright (c) 2010 maidsafe.net limited
All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

    * Redistributions of source code must retain the above copyright notice,
    this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright notice,
    this list of conditions and the following disclaimer in the documentation
    and/or other materials provided with the distribution.
    * Neither the name of the maidsafe.net limited nor the names of its
    contributors may be used to endorse or promote products derived from this
    software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include "maidsafe/dht/node_id.h"
#include <bitset>
#include "maidsafe/dht/log.h"
#include "maidsafe/common/utils.h"

namespace maidsafe {

namespace dht {

size_t BitToByteCount(const size_t &bit_count) {
  return static_cast<size_t>(0.999999 + static_cast<double>(bit_count) / 8);
}

NodeId::NodeId() : raw_id_(kZeroId) {}

NodeId::NodeId(const NodeId &other) : raw_id_(other.raw_id_) {}

NodeId::NodeId(const KadIdType &type) : raw_id_(kKeySizeBytes, -1) {
  switch (type) {
    case kMaxId :
      break;  // already set
    case kRandomId :
      std::generate(raw_id_.begin(), raw_id_.end(),
                    std::bind(&RandomUint32));
      break;
    default :
      break;
  }
}

NodeId::NodeId(const std::string &id) : raw_id_(id) {
  if (!IsValid())
    raw_id_.clear();
}

NodeId::NodeId(const std::string &id, const EncodingType &encoding_type)
    : raw_id_() {
  try {
    switch (encoding_type) {
      case kBinary : DecodeFromBinary(id);
        break;
      case kHex : raw_id_ = DecodeFromHex(id);
        break;
      case kBase32 : raw_id_ = DecodeFromBase32(id);
        break;
      case kBase64 : raw_id_ = DecodeFromBase64(id);
        break;
      default : raw_id_ = id;
    }
  }
  catch(const std::exception &e) {
    DLOG(ERROR) << "NodeId Ctor: " << e.what();
    raw_id_.clear();
    return;
  }
  if (!IsValid())
    raw_id_.clear();
}

NodeId::NodeId(const uint16_t &power) : raw_id_(kZeroId) {
  if (power >= kKeySizeBits) {
    raw_id_.clear();
    return;
  }
  uint16_t shift = power % 8;
  if (shift != 0) {
    raw_id_[kKeySizeBytes - BitToByteCount(power)] += 1 << shift;
  } else {
    raw_id_[kKeySizeBytes - BitToByteCount(power) - 1] = 1;
  }
}

NodeId::NodeId(const NodeId &id1, const NodeId &id2) : raw_id_(kZeroId) {
  if (!id1.IsValid() || !id2.IsValid()) {
    raw_id_.clear();
    return;
  }
  if (id1 == id2) {
    raw_id_ = id1.raw_id_;
    return;
  }
  std::string min_id(id1.raw_id_), max_id(id2.raw_id_);
  if (id1 > id2) {
    max_id = id1.raw_id_;
    min_id = id2.raw_id_;
  }
  bool less_than_upper_limit(false);
  bool greater_than_lower_limit(false);
  unsigned char max_id_char(0), min_id_char(0), this_char(0);
  for (size_t pos = 0; pos < kKeySizeBytes; ++pos) {
    if (!less_than_upper_limit) {
      max_id_char = max_id[pos];
      min_id_char = greater_than_lower_limit ? 0 : min_id[pos];
      if (max_id_char == 0) {
        raw_id_[pos] = 0;
      } else {
        raw_id_[pos] = (RandomUint32() % (max_id_char - min_id_char + 1))
                       + min_id_char;
        this_char = raw_id_[pos];
        less_than_upper_limit = (this_char < max_id_char);
        greater_than_lower_limit = (this_char > min_id_char);
      }
    } else if (!greater_than_lower_limit) {
      min_id_char = min_id[pos];
      raw_id_[pos] = static_cast<char>(RandomUint32() % (256 - min_id_char))
                     + min_id_char;
      this_char = raw_id_[pos];
      greater_than_lower_limit = (this_char > min_id_char);
    } else {
      raw_id_[pos] = static_cast<char>(RandomUint32());
    }
  }
}

std::string NodeId::EncodeToBinary() const {
  std::string binary;
  binary.reserve(kKeySizeBytes);
  for (size_t i = 0; i < kKeySizeBytes; ++i) {
    std::bitset<8> temp(static_cast<int>(raw_id_[i]));
    binary += temp.to_string();
  }
  return binary;
}

void NodeId::DecodeFromBinary(const std::string &binary_id) {
  std::bitset<kKeySizeBits> binary_bitset(binary_id);
  if (!IsValid()) {
    raw_id_.assign(kKeySizeBytes, 0);
  }
  for (size_t i = 0; i < kKeySizeBytes; ++i) {
    std::bitset<8> temp(binary_id.substr(i * 8, 8));
    raw_id_[i] = static_cast<char>(temp.to_ulong());
  }
}

bool NodeId::CloserToTarget(const NodeId &id1,
                            const NodeId &id2,
                            const NodeId &target_id) {
  if (!id1.IsValid() || !id2.IsValid() || !target_id.IsValid())
    return false;
  std::string raw_id1(id1.raw_id_);
  std::string raw_id2(id2.raw_id_);
  std::string raw_id_target(target_id.raw_id_);
  for (uint16_t i = 0; i < kKeySizeBytes; ++i) {
    unsigned char result1 = raw_id1[i] ^ raw_id_target[i];
    unsigned char result2 = raw_id2[i] ^ raw_id_target[i];
    if (result1 != result2)
      return result1 < result2;
  }
  return false;
}

const std::string NodeId::String() const {
  return raw_id_;
}

const std::string NodeId::ToStringEncoded(
    const EncodingType &encoding_type) const {
  if (!IsValid())
    return "";
  switch (encoding_type) {
    case kBinary:
      return EncodeToBinary();
    case kHex:
      return EncodeToHex(raw_id_);
    case kBase32:
      return EncodeToBase32(raw_id_);
    case kBase64:
      return EncodeToBase64(raw_id_);
    default:
      return raw_id_;
  }
}

bool NodeId::IsValid() const {
  return raw_id_.size() == kKeySizeBytes;
}

bool NodeId::operator == (const NodeId &rhs) const {
  return raw_id_ == rhs.raw_id_;
}

bool NodeId::operator != (const NodeId &rhs) const {
  return raw_id_ != rhs.raw_id_;
}

bool NodeId::operator < (const NodeId &rhs) const {
  return raw_id_ < rhs.raw_id_;
}

bool NodeId::operator > (const NodeId &rhs) const {
  return raw_id_ > rhs.raw_id_;
}

bool NodeId::operator <= (const NodeId &rhs) const {
  return raw_id_ <= rhs.raw_id_;
}

bool NodeId::operator >= (const NodeId &rhs) const {
  return raw_id_ >= rhs.raw_id_;
}

NodeId& NodeId::operator = (const NodeId &rhs) {
  this->raw_id_ = rhs.raw_id_;
  return *this;
}

const NodeId NodeId::operator ^ (const NodeId &rhs) const {
  NodeId result;
  std::string::const_iterator this_it = raw_id_.begin();
  std::string::const_iterator rhs_it = rhs.raw_id_.begin();
  std::string::iterator result_it = result.raw_id_.begin();
  for (; this_it != raw_id_.end(); ++this_it, ++rhs_it, ++result_it)
    *result_it = *this_it ^ *rhs_it;
  return result;
}

std::string DebugId(const NodeId &node_id) {
  std::string hex(node_id.ToStringEncoded(NodeId::kHex));
  return hex.substr(0, 7) + ".." +hex.substr(hex.size() - 7);
}

}  // namespace dht

}  // namespace maidsafe

Added wiki_references/2017/software/MaidSafe_net/src_from_GitHub/the_repository_clones/MaidSafe-DHT/src/maidsafe/dht/node_id.h version [4550104f1b].

















































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
/* Copyright (c) 2010 maidsafe.net limited
All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

    * Redistributions of source code must retain the above copyright notice,
    this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright notice,
    this list of conditions and the following disclaimer in the documentation
    and/or other materials provided with the distribution.
    * Neither the name of the maidsafe.net limited nor the names of its
    contributors may be used to endorse or promote products derived from this
    software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#ifndef MAIDSAFE_DHT_NODE_ID_H_
#define MAIDSAFE_DHT_NODE_ID_H_

#include <cstdint>
#include <string>
#include <vector>
#include "boost/serialization/nvp.hpp"
#include "maidsafe/common/platform_config.h"
#include "maidsafe/dht/config.h"
#include "maidsafe/dht/version.h"

#if MAIDSAFE_DHT_VERSION != 3200
#  error This API is not compatible with the installed library.\
    Please update the maidsafe-dht library.
#endif


namespace maidsafe {

namespace dht {

/**
* The size of DHT keys and node IDs in bits.
**/
const uint16_t kKeySizeBits = 8 * kKeySizeBytes;

const std::string kZeroId(kKeySizeBytes, 0);

size_t BitToByteCount(const size_t &bit_count);

/**
* @class NodeId
* Class used to contain a valid kademlia id in the range [0, 2 ^ kKeySizeBits)
*/

class NodeId {
 public:
  enum KadIdType { kMaxId, kRandomId };
  enum EncodingType { kBinary, kHex, kBase32, kBase64 };
  /**
  * Default Constructor.  Creates an id equal to 0.
  **/
  NodeId();

  /**
  * Copy contructor.
  * @param rhs a NodeId object.
  */
  NodeId(const NodeId &other);

  /**
  * Constructor.  Creates an id = (2 ^ kKeySizeBits) - 1 or a random id in the
  * interval [0, 2 ^ kKeySizeBits).
  * @param type Type of id to be created (kMaxId or kRandomId).
  */
  explicit NodeId(const KadIdType &type);

  /**
  * Constructor.  Creates a NodeId from a raw (decoded) string.
  * @param id string representing the decoded kademlia id.
  */
  explicit NodeId(const std::string &id);

  /**
  * Constructor.  Creates a NodeId from an encoded string.
  * @param id string representing the kademlia id.
  * @param encoding_type Type of encoding to use.
  */
  NodeId(const std::string &id, const EncodingType &encoding_type);

  /**
  * Constructor.  Creates a NodeId equal to 2 ^ power.
  * @param power < kKeySizeBytes.
  */
  explicit NodeId(const uint16_t &power);

  /**
  * Constructor.  Creates a random NodeId in range [lower ID, higher ID]
  * Prefer to pass lower ID as id1.
  * @param id1 ID upper or lower limit.
  * @param id2 ID upper or lower limit.
  */
  NodeId(const NodeId &id1, const NodeId &id2);

  /**
  * Checks if id1 is closer in XOR distance to target_id than id2.
  * @param id1 NodeId object.
  * @param id2 NodeId object.
  * @param target_id NodeId object to which id1 and id2 distance is computed to
  * be compared.
  * @return True if id1 is closer to target_id than id2, otherwise false.
  */
  static bool CloserToTarget(const NodeId &id1,
                             const NodeId &id2,
                             const NodeId &target_id);

  /** Decoded representation of the kademlia id.
  * @return A decoded string representation of the kademlia id.
  */
  const std::string String() const;

  /** Encoded representation of the kademlia id.
  * @param encoding_type Type of encoding to use.
  * @return An encoded string representation of the kademlia id.
  */
  const std::string ToStringEncoded(const EncodingType &encoding_type) const;

  /**
  * Checks that raw_id_ has size kKeySizeBytes.
  */
  bool IsValid() const;

  bool operator == (const NodeId &rhs) const;
  bool operator != (const NodeId &rhs) const;
  bool operator < (const NodeId &rhs) const;
  bool operator > (const NodeId &rhs) const;
  bool operator <= (const NodeId &rhs) const;
  bool operator >= (const NodeId &rhs) const;
  NodeId& operator = (const NodeId &rhs);

  /**
  * XOR distance between two kademlia IDs.  XOR bit to bit.
  * @param rhs NodeId to which this is XOR
  * @return a NodeId object that is equal to this XOR rhs
  */
  const NodeId operator ^ (const NodeId &rhs) const;

 private:
  std::string EncodeToBinary() const;
  void DecodeFromBinary(const std::string &binary_id);
  std::string raw_id_;
};

/** Returns an abbreviated hex representation of node_id */
std::string DebugId(const NodeId &node_id);

}  // namespace dht

}  // namespace maidsafe



namespace mk = maidsafe::dht;

namespace boost {

namespace serialization {

#ifdef __MSVC__
#  pragma warning(disable: 4127)
#endif
template <typename Archive>
void serialize(Archive &archive,                              // NOLINT (Fraser)
               mk::NodeId &node_id,
               const unsigned int& /*version*/) {
  std::string node_id_local;
  if (Archive::is_saving::value) {
    node_id_local = (node_id.ToStringEncoded(mk::NodeId::kBase64));
  }
  archive& boost::serialization::make_nvp("node_id", node_id_local);
  if (Archive::is_loading::value) {
    node_id = mk::NodeId(node_id_local, mk::NodeId::kBase64);
  }
#ifdef __MSVC__
#  pragma warning(default: 4127)
#endif
}

}  // namespace serialization

}  // namespace boost

#endif  // MAIDSAFE_DHT_NODE_ID_H_

Added wiki_references/2017/software/MaidSafe_net/src_from_GitHub/the_repository_clones/MaidSafe-DHT/src/maidsafe/dht/node_impl.cc version [8ffc18ba0e].

























































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
/* Copyright (c) 2009 maidsafe.net limited
All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

    * Redistributions of source code must retain the above copyright notice,
    this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright notice,
    this list of conditions and the following disclaimer in the documentation
    and/or other materials provided with the distribution.
    * Neither the name of the maidsafe.net limited nor the names of its
    contributors may be used to endorse or promote products derived from this
    software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include <algorithm>
#include <functional>
#include <map>

#include "maidsafe/common/rsa.h"
#include "maidsafe/common/utils.h"
#include "maidsafe/transport/rudp_transport.h"
#include "maidsafe/transport/tcp_transport.h"

#include "maidsafe/dht/log.h"
#include "maidsafe/dht/node_impl.h"
#include "maidsafe/dht/data_store.h"
#ifdef __MSVC__
#  pragma warning(push)
#  pragma warning(disable: 4127 4244 4267)
#endif
#include "maidsafe/dht/kademlia.pb.h"
#ifdef __MSVC__
#  pragma warning(pop)
#endif
#include "maidsafe/dht/node_id.h"
#include "maidsafe/dht/rpcs.h"
#include "maidsafe/dht/return_codes.h"
#include "maidsafe/dht/routing_table.h"
#include "maidsafe/dht/service.h"
#include "maidsafe/dht/utils.h"

namespace args = std::placeholders;

namespace maidsafe {
namespace dht {

namespace {
bool FindResultError(int result) {
  return (result != kSuccess &&
          result != kFoundCachedCopyHolder &&
          result != kFailedToFindValue);
}
}  // unnamed namespace

NodeImpl::NodeImpl(boost::asio::io_service &asio_service,     // NOLINT (Fraser)
                   TransportPtr listening_transport,
                   MessageHandlerPtr message_handler,
                   KeyPairPtr default_asym_key_pair,
                   bool client_only_node,
                   const uint16_t &k,
                   const uint16_t &alpha,
                   const uint16_t &beta,
                   const bptime::time_duration &mean_refresh_interval)
    : asio_service_(asio_service),
      listening_transport_(listening_transport),
      message_handler_(message_handler),
      default_public_key_(),
      default_private_key_(),
      on_online_status_change_(new OnOnlineStatusChangePtr::element_type),
      client_only_node_(client_only_node),
      k_(k),
      kAlpha_(alpha),
      kBeta_(beta),
      kMeanRefreshInterval_(mean_refresh_interval.is_special() ? 3600 :
                            mean_refresh_interval.total_seconds()),
      kDataStoreCheckInterval_(bptime::seconds(1)),
      data_store_(),
      service_(),
      routing_table_(),
      rpcs_(),
      contact_validation_getter_(std::bind(&StubContactValidationGetter,
                                           args::_1, args::_2)),
      contact_validator_(std::bind(&StubContactValidator, args::_1, args::_2,
                                   args::_3)),
      validate_functor_(std::bind(&StubValidate, args::_1, args::_2, args::_3)),
      contact_(),
      joined_(false),
      ping_oldest_contact_(),
      validate_contact_(),
      ping_down_contact_(),
      refresh_data_store_timer_(asio_service_),
      join_mutex_(),
      check_cache_functor_() {
  if (default_asym_key_pair) {
    default_private_key_ = PrivateKeyPtr(
        new asymm::PrivateKey(default_asym_key_pair->private_key));
    default_public_key_ = PublicKeyPtr(
        new asymm::PublicKey(default_asym_key_pair->public_key));
  }
}

NodeImpl::~NodeImpl() {
  if (joined_)
    Leave(nullptr);
}

void NodeImpl::Join(const NodeId &node_id,
                    std::vector<Contact> bootstrap_contacts,
                    JoinFunctor callback) {
  if (joined_) {
    asio_service_.post(std::bind(&NodeImpl::JoinSucceeded, this, callback));
    return;
  }

  // Remove our own Contact if present
  bootstrap_contacts.erase(
      std::remove_if(bootstrap_contacts.begin(), bootstrap_contacts.end(),
          std::bind(&HasId, args::_1, node_id)), bootstrap_contacts.end());

  if (!client_only_node_ && listening_transport_->listening_port() == 0) {
    return asio_service_.post(std::bind(&NodeImpl::JoinFailed, this, callback,
                                        kNotListening));
  }

  // TODO(Viv) Remove Pub Key From Class Member and take in as Argument
  if (!default_private_key_ || !default_public_key_) {
    DLOG(INFO) << "Creating Keypair";
    asymm::Keys key_pair;
    asymm::GenerateKeyPair(&key_pair);
    default_private_key_.reset(new asymm::PrivateKey(key_pair.private_key));
    default_public_key_.reset(new asymm::PublicKey(key_pair.public_key));
  } else {
    DLOG(INFO) << EncodeToHex(node_id.String());
  }

  if (!rpcs_) {
    rpcs_.reset(new Rpcs<transport::TcpTransport>(asio_service_,
                                                  default_private_key_));
  }
  // TODO(Fraser#5#): 2011-07-08 - Need to update code for local endpoints.
  if (!client_only_node_) {
    std::vector<transport::Endpoint> local_endpoints;
    // Create contact_ information for node and set contact for Rpcs
    transport::Endpoint endpoint;
    endpoint.ip = listening_transport_->transport_details().endpoint.ip;
    endpoint.port = listening_transport_->transport_details().endpoint.port;
    local_endpoints.push_back(endpoint);
    contact_ =
        Contact(node_id, endpoint, local_endpoints,
                listening_transport_->transport_details().rendezvous_endpoint,
                false, false, node_id.String(),
                *default_public_key_, "");
    rpcs_->set_contact(contact_);
  } else {
    contact_ = Contact(node_id, transport::Endpoint(),
                       std::vector<transport::Endpoint>(),
                       transport::Endpoint(), false, false,
                       node_id.String(),
                       *default_public_key_, "");
    protobuf::Contact proto_contact(ToProtobuf(contact_));
    proto_contact.set_node_id(NodeId().String());
    rpcs_->set_contact(FromProtobuf(proto_contact));
  }

  routing_table_.reset(new RoutingTable(node_id, k_));
  // Connect the slots to the routing table signals.
  ConnectPingOldestContact();
  ConnectValidateContact();
  ConnectPingDownContact();

  if (bootstrap_contacts.empty()) {
    // This is the first node on the network.
    asio_service_.post(std::bind(&NodeImpl::JoinSucceeded, this, callback));
    return;
  }

  // Ensure bootstrap contacts are valid
  bootstrap_contacts.erase(std::remove(bootstrap_contacts.begin(),
                                       bootstrap_contacts.end(), Contact()),
                           bootstrap_contacts.end());
  if (bootstrap_contacts.empty()) {
    return asio_service_.post(std::bind(&NodeImpl::JoinFailed, this, callback,
                                        kInvalidBootstrapContacts));
  }

  OrderedContacts search_contacts(CreateOrderedContacts(node_id));
  search_contacts.insert(bootstrap_contacts.front());
  bootstrap_contacts.erase(bootstrap_contacts.begin());
  FindValueArgsPtr find_value_args(
      new FindValueArgs(node_id, k_, search_contacts, true,
                        default_private_key_,
                        std::bind(&NodeImpl::JoinFindValueCallback, this,
                                  args::_1, bootstrap_contacts, node_id,
                                  callback, true)));

  DLOG(INFO) << "Before StartLookup";
  StartLookup(find_value_args);
}

void NodeImpl::JoinFindValueCallback(FindValueReturns find_value_returns,
                                     std::vector<Contact> bootstrap_contacts,
                                     const NodeId &node_id,
                                     JoinFunctor callback,
                                     bool none_reached) {
  if (!find_value_returns.values_and_signatures.empty()) {
    JoinFailed(callback, kValueAlreadyExists);
    return;
  }
  if (none_reached && !NodeContacted(find_value_returns.return_code) &&
      bootstrap_contacts.empty()) {
    JoinFailed(callback, kContactFailedToRespond);
  } else if ((find_value_returns.return_code != kFailedToFindValue) &&
             !bootstrap_contacts.empty()) {
    if (NodeContacted(find_value_returns.return_code))
      none_reached = false;
    OrderedContacts search_contacts(CreateOrderedContacts(node_id));
    search_contacts.insert(bootstrap_contacts.front());
    bootstrap_contacts.erase(bootstrap_contacts.begin());
    FindValueArgsPtr find_value_args(
        new FindValueArgs(node_id, k_, search_contacts, true,
            default_private_key_, std::bind(&NodeImpl::JoinFindValueCallback,
                                         this, args::_1, bootstrap_contacts,
                                         node_id, callback, none_reached)));
    StartLookup(find_value_args);
  } else {
    JoinSucceeded(callback);
  }
}

void NodeImpl::JoinSucceeded(JoinFunctor callback) {
  boost::mutex::scoped_lock lock(join_mutex_);
  joined_ = true;
  if (!client_only_node_) {
    data_store_.reset(new DataStore(kMeanRefreshInterval_));
    service_.reset(new Service(routing_table_, data_store_,
                               default_private_key_, k_));
    service_->set_node_joined(true);
    service_->set_node_contact(contact_);
    service_->ConnectToSignals(message_handler_);
    service_->set_contact_validation_getter(contact_validation_getter_);
    service_->set_contact_validator(contact_validator_);
    service_->set_validate(validate_functor_);
    service_->set_check_cache_functor(check_cache_functor_);
    refresh_data_store_timer_.expires_from_now(kDataStoreCheckInterval_);
    refresh_data_store_timer_.async_wait(
        std::bind(&NodeImpl::RefreshDataStore, this, args::_1));
    data_store_->set_debug_id(DebugId(contact_));
  }
  callback(kSuccess);
}

void NodeImpl::JoinFailed(JoinFunctor callback, int result) {
  callback(result);
}

void NodeImpl::Leave(std::vector<Contact> *bootstrap_contacts) {
  joined_ = false;
  refresh_data_store_timer_.cancel();
  ping_oldest_contact_.disconnect();
  validate_contact_.disconnect();
  ping_down_contact_.disconnect();
  if (!client_only_node_)
    service_.reset();
  GetBootstrapContacts(bootstrap_contacts);
}

template <typename T>
void NodeImpl::NotJoined(T callback) {
  callback(kNotJoined);
}

template <>
void NodeImpl::NotJoined<FindValueFunctor> (FindValueFunctor callback) {
  callback(FindValueReturns(kNotJoined, std::vector<ValueAndSignature>(),
                            std::vector<Contact>(), Contact(), Contact()));
}

template <>
void NodeImpl::NotJoined<FindNodesFunctor> (FindNodesFunctor callback) {
  callback(kNotJoined, std::vector<Contact>());
}

template <>
void NodeImpl::NotJoined<GetContactFunctor> (GetContactFunctor callback) {
  callback(kNotJoined, Contact());
}

template <typename T>
void NodeImpl::FailedValidation(T callback) {
  callback(kFailedValidation);
}

OrderedContacts NodeImpl::GetClosestContactsLocally(
    const Key &key,
    const uint16_t &total_contacts) {
  std::vector<Contact> close_nodes, excludes;
  routing_table_->GetCloseContacts(key, total_contacts, excludes, &close_nodes);
  OrderedContacts close_contacts(CreateOrderedContacts(close_nodes.begin(),
                                                       close_nodes.end(), key));
  // This node's ID will not be held in the routing table, so add it now.  The
  // iterative lookup will take care of the (likely) case that it's not within
  // the requested number of closest contacts.
  if (!client_only_node_)
    close_contacts.insert(contact_);
  return close_contacts;
}

int NodeImpl::SignIfEmpty(const std::string &value,
                          PrivateKeyPtr private_key,
                          std::string *signature) {
  if (signature->empty())
    return asymm::Sign(value, *private_key, signature);
  return kSuccess;
}

void NodeImpl::Store(const Key &key,
                     const std::string &value,
                     const std::string &signature,
                     const bptime::time_duration &ttl,
                     PrivateKeyPtr private_key,
                     StoreFunctor callback) {
  if (!joined_) {
    return asio_service_.post(std::bind(&NodeImpl::NotJoined<StoreFunctor>,
                                        this, callback));
  }

  if (!private_key)
    private_key = default_private_key_;

  std::string sig(signature);
  if (SignIfEmpty(value, private_key, &sig) != kSuccess) {
    return asio_service_.post(
        std::bind(&NodeImpl::FailedValidation<StoreFunctor>, this, callback));
  }

  OrderedContacts close_contacts(GetClosestContactsLocally(key, k_));
  StoreArgsPtr store_args(new StoreArgs(key, k_, close_contacts,
      static_cast<int>(k_ * kMinSuccessfulPecentageStore), value, sig, ttl,
      private_key, callback));
  StartLookup(store_args);
}

void NodeImpl::Delete(const Key &key,
                      const std::string &value,
                      const std::string &signature,
                      PrivateKeyPtr private_key,
                      DeleteFunctor callback) {
  if (!joined_) {
    return asio_service_.post(std::bind(&NodeImpl::NotJoined<DeleteFunctor>,
                                        this, callback));
  }

  if (!private_key)
    private_key = default_private_key_;

  std::string sig(signature);
  if (SignIfEmpty(value, private_key, &sig) != kSuccess) {
    return asio_service_.post(
        std::bind(&NodeImpl::FailedValidation<DeleteFunctor>, this, callback));
  }

  OrderedContacts close_contacts(GetClosestContactsLocally(key, k_));
  DeleteArgsPtr delete_args(new DeleteArgs(key, k_, close_contacts,
      static_cast<int>(k_ * kMinSuccessfulPecentageDelete), value, sig,
      private_key, callback));
  StartLookup(delete_args);
}

void NodeImpl::Update(const Key &key,
                      const std::string &new_value,
                      const std::string &new_signature,
                      const std::string &old_value,
                      const std::string &old_signature,
                      const bptime::time_duration &ttl,
                      PrivateKeyPtr private_key,
                      UpdateFunctor callback) {
  if (!joined_) {
    return asio_service_.post(std::bind(&NodeImpl::NotJoined<UpdateFunctor>,
                                        this, callback));
  }

  if (!private_key)
    private_key = default_private_key_;

  std::string new_sig(new_signature), old_sig(old_signature);
  if (SignIfEmpty(old_value, private_key, &old_sig) != kSuccess ||
      SignIfEmpty(new_value, private_key, &new_sig) != kSuccess) {
    return asio_service_.post(
        std::bind(&NodeImpl::FailedValidation<UpdateFunctor>, this, callback));
  }

  OrderedContacts close_contacts(GetClosestContactsLocally(key, k_));
  UpdateArgsPtr update_args(new UpdateArgs(key, k_, close_contacts,
      static_cast<int>(k_ * kMinSuccessfulPecentageUpdate), old_value,
      old_sig, new_value, new_sig, ttl, private_key, callback));
  StartLookup(update_args);
}

void NodeImpl::FindValue(const Key &key,
                         PrivateKeyPtr private_key,
                         FindValueFunctor callback,
                         const uint16_t &extra_contacts,
                         bool cache) {
  if (!joined_) {
    return asio_service_.post(std::bind(&NodeImpl::NotJoined<FindValueFunctor>,
                                        this, callback));
  }
  if (!private_key)
    private_key = default_private_key_;
  OrderedContacts close_contacts(
      GetClosestContactsLocally(key, k_ + extra_contacts));

  // If this node is not client-only & is within the k_ closest do a local find.
  if (!client_only_node_) {
    uint16_t closest_count(0);
    auto itr(close_contacts.begin());
    while (itr != close_contacts.end() && closest_count != k_) {
      if (*itr == contact_) {
        std::vector<ValueAndSignature> values_and_sigs;
        std::vector<Contact> contacts;
        if (check_cache_functor_ && check_cache_functor_(key.String())) {
          FindValueReturns find_value_returns(kFoundCachedCopyHolder,
                                              values_and_sigs, contacts,
                                              contact_, Contact());
          asio_service_.post(std::bind(&NodeImpl::FoundValueLocally, this,
                                       find_value_returns, callback));
          return;
        }
        if (data_store_->GetValues(key.String(), &values_and_sigs)) {
          FindValueReturns find_value_returns(kSuccess, values_and_sigs,
                                              contacts, Contact(), Contact());
          asio_service_.post(std::bind(&NodeImpl::FoundValueLocally, this,
                                       find_value_returns, callback));
          return;
        }
      }
      ++itr;
      ++closest_count;
    }
  }

  FindValueArgsPtr find_value_args(new FindValueArgs(key, k_ + extra_contacts,
      close_contacts, cache, private_key, callback));
  StartLookup(find_value_args);
}

void NodeImpl::FoundValueLocally(const FindValueReturns &find_value_returns,
                                 FindValueFunctor callback) {
  callback(find_value_returns);
}

void NodeImpl::FindNodes(const Key &key,
                         FindNodesFunctor callback,
                         const uint16_t &extra_contacts) {
  if (!joined_) {
    return asio_service_.post(std::bind(&NodeImpl::NotJoined<FindNodesFunctor>,
                                        this, callback));
  }
  OrderedContacts close_contacts(
      GetClosestContactsLocally(key, k_ + extra_contacts));
  FindNodesArgsPtr find_nodes_args(new FindNodesArgs(key, k_ + extra_contacts,
      close_contacts, default_private_key_, callback));
  StartLookup(find_nodes_args);
}

void NodeImpl::GetContact(const NodeId &node_id, GetContactFunctor callback) {
  if (node_id == contact_.node_id()) {
    asio_service_.post(std::bind(&NodeImpl::GetOwnContact, this, callback));
    return;
  }

  if (!joined_) {
    return asio_service_.post(std::bind(&NodeImpl::NotJoined<GetContactFunctor>,
                                        this, callback));
  }

  std::vector<Contact> close_nodes, excludes;
  routing_table_->GetCloseContacts(node_id, k_, excludes, &close_nodes);
  OrderedContacts close_contacts(CreateOrderedContacts(close_nodes.begin(),
                                                       close_nodes.end(),
                                                       node_id));
  // If we have the contact in our own routing table, ping it, otherwise start
  // a lookup for it.
  if ((*close_contacts.begin()).node_id() == node_id) {
    rpcs_->Ping(default_private_key_,
                *close_contacts.begin(),
                std::bind(&NodeImpl::GetContactPingCallback, this, args::_1,
                          args::_2, *close_contacts.begin(), callback));
  } else {
    GetContactArgsPtr get_contact_args(
        new GetContactArgs(node_id, k_, close_contacts, default_private_key_,
                           callback));
    StartLookup(get_contact_args);
  }
}

void NodeImpl::SetContactValidationGetter(
    asymm::GetPublicKeyAndValidationFunctor contact_validation_getter) {
  contact_validation_getter_ = contact_validation_getter;
  if (service_)
    service_->set_contact_validation_getter(contact_validation_getter_);
}

void NodeImpl::SetContactValidator(
    asymm::ValidatePublicKeyFunctor contact_validator) {
  contact_validator_ = contact_validator;
  if (service_)
    service_->set_contact_validator(contact_validator_);
}

void NodeImpl::SetValidate(asymm::ValidateFunctor validate_functor) {
  validate_functor_ = validate_functor;
  if (service_)
    service_->set_validate(validate_functor_);
}

void NodeImpl::GetOwnContact(GetContactFunctor callback) {
  callback(kSuccess, contact_);
}

void NodeImpl::GetContactPingCallback(RankInfoPtr rank_info,
                                      int result,
                                      Contact peer,
                                      GetContactFunctor callback) {
  AsyncHandleRpcCallback(peer, rank_info, result);
  if (result == kSuccess)
    callback(kSuccess, peer);
  else
    callback(kFailedToGetContact, Contact());
}

void NodeImpl::Ping(const Contact &contact, PingFunctor callback) {
  if (!joined_) {
    return asio_service_.post(std::bind(&NodeImpl::NotJoined<PingFunctor>,
                                        this, callback));
  }
  rpcs_->Ping(default_private_key_,
              contact,
              std::bind(&NodeImpl::PingCallback, this, args::_1, args::_2,
                        contact, callback));
}

void NodeImpl::PingCallback(RankInfoPtr rank_info,
                            int result,
                            Contact peer,
                            PingFunctor callback) {
  AsyncHandleRpcCallback(peer, rank_info, result);
  callback(result);
}

void NodeImpl::SetLastSeenToNow(const Contact &contact) {
  Contact result;
  if (routing_table_->GetContact(contact.node_id(), &result) != kSuccess)
    return;
  // If the contact exists in the routing table, adding it again will set its
  // last_seen to now.
  routing_table_->AddContact(contact, RankInfoPtr());
}

void NodeImpl::IncrementFailedRpcs(const Contact &contact) {
  routing_table_->IncrementFailedRpcCount(contact.node_id());
}

void NodeImpl::UpdateRankInfo(const Contact &contact, RankInfoPtr rank_info) {
  routing_table_->UpdateRankInfo(contact.node_id(), rank_info);
}

RankInfoPtr NodeImpl::GetLocalRankInfo(const Contact &contact) const {
  return routing_table_->GetLocalRankInfo(contact);
}

void NodeImpl::GetAllContacts(std::vector<Contact> *contacts) {
  routing_table_->GetAllContacts(contacts);
}

void NodeImpl::GetBootstrapContacts(std::vector<Contact> *contacts) {
  if (!contacts)
    return;
  routing_table_->GetBootstrapContacts(contacts);

  // Allow time to validate and add the first node on the network in the case
  // where this node is the second.
  int attempts(0);
  const int kMaxAttempts(50);
  while (attempts != kMaxAttempts && contacts->empty()) {
    Sleep(bptime::milliseconds(100));
    routing_table_->GetBootstrapContacts(contacts);
    ++attempts;
  }

  if (contacts->empty())
    contacts->push_back(contact_);
}

void NodeImpl::StartLookup(LookupArgsPtr lookup_args) {
  BOOST_ASSERT(lookup_args->kNumContactsRequested >= k_);
  boost::mutex::scoped_lock lock(lookup_args->mutex);
  DoLookupIteration(lookup_args);
}

void NodeImpl::DoLookupIteration(LookupArgsPtr lookup_args) {
  lookup_args->rpcs_in_flight_for_current_iteration = 0;
  lookup_args->lookup_phase_complete = false;
  size_t good_contact_count(0), pending_result_count(0);
  bool wait_for_in_flight_rpcs(false);
  auto itr = lookup_args->lookup_contacts.find(contact_);
  if (itr != lookup_args->lookup_contacts.end() && !client_only_node_) {
    (*itr).second.rpc_state = ContactInfo::kRepliedOK;
  }
  itr = lookup_args->lookup_contacts.begin();
  while (itr != lookup_args->lookup_contacts.end() &&
         !wait_for_in_flight_rpcs) {
    switch ((*itr).second.rpc_state) {
      case ContactInfo::kNotSent: {
        if (!client_only_node_ && (*itr).first == contact_) {
          // If this node isn't a client and is the current contact, we've
          // already added the closest it knows of at the start of the op.
          (*itr).second.rpc_state = ContactInfo::kRepliedOK;
        } else {
          if (lookup_args->kOperationType == LookupArgs::kFindValue) {
            DLOG(INFO) << "Sending FindValue " << DebugId(lookup_args->kTarget)
                       << " to " << DebugId((*itr).first);
            rpcs_->FindValue(lookup_args->kTarget,
                             lookup_args->kNumContactsRequested,
                             lookup_args->private_key,
                             (*itr).first,
                             std::bind(&NodeImpl::IterativeFindCallback,
                                       this, args::_1, args::_2, args::_3,
                                       args::_4, args::_5, (*itr).first,
                                       lookup_args));
          } else {
            rpcs_->FindNodes(lookup_args->kTarget,
                             lookup_args->kNumContactsRequested,
                             default_private_key_,
                             (*itr).first,
                             std::bind(&NodeImpl::IterativeFindCallback,
                                       this, args::_1, args::_2,
                                       std::vector<ValueAndSignature>(),
                                       args::_3, Contact(), (*itr).first,
                                       lookup_args));
          }
          ++lookup_args->total_lookup_rpcs_in_flight;
          ++lookup_args->rpcs_in_flight_for_current_iteration;
          (*itr).second.rpc_state = ContactInfo::kSent;
        }
        break;
      }
      case ContactInfo::kSent: {
        ++pending_result_count;
        (*itr).second.rpc_state = ContactInfo::kDelayed;
        break;
      }
      case ContactInfo::kDelayed: {
        ++pending_result_count;
        break;
      }
      case ContactInfo::kRepliedOK: {
        ++good_contact_count;
        break;
      }
      default: break;
    }
    wait_for_in_flight_rpcs =
        (lookup_args->rpcs_in_flight_for_current_iteration == kAlpha_) ||
        ((lookup_args->rpcs_in_flight_for_current_iteration +
            pending_result_count + good_contact_count) ==
            lookup_args->kNumContactsRequested);
    ++itr;
  }
}

void NodeImpl::IterativeFindCallback(
    RankInfoPtr rank_info,
    int result,
    const std::vector<ValueAndSignature> &values_and_signatures,
    const std::vector<Contact> &contacts,
    const Contact &cached_copy_holder,
    Contact peer,
    LookupArgsPtr lookup_args) {
  // It is only OK for a node to return no meaningful information if this is
  // the second to join the network (peer being the first)
  boost::mutex::scoped_lock lock(lookup_args->mutex);
  bool second_node(false);
  if (result == kIterativeLookupFailed &&
      lookup_args->lookup_contacts.size() == 1) {
    result = kSuccess;
    second_node = true;
  }

  AsyncHandleRpcCallback(peer, rank_info, result);
  auto this_peer(lookup_args->lookup_contacts.find(peer));
  --lookup_args->total_lookup_rpcs_in_flight;
  BOOST_ASSERT(lookup_args->total_lookup_rpcs_in_flight >= 0);
  if (this_peer == lookup_args->lookup_contacts.end()) {
    DLOG(ERROR) << DebugId(contact_) << ": Can't find " << DebugId(peer)
                << " in lookup args.";
    return;
  }

  // Note - if the RPC isn't from this iteration, it will be marked as kDelayed.
  if ((*this_peer).second.rpc_state == ContactInfo::kSent)
    --lookup_args->rpcs_in_flight_for_current_iteration;

  // If the RPC returned an error, move peer to the downlist.
  if (FindResultError(result)) {
    lookup_args->downlist.insert(*this_peer);
    lookup_args->lookup_contacts.erase(this_peer);
  }

  // If the lookup has already been completed, do nothing unless this is also
  // the last callback, in which case, send the downlist notifications out.
  if (lookup_args->lookup_phase_complete) {
    if (lookup_args->total_lookup_rpcs_in_flight == 0)
      SendDownlist(lookup_args->downlist);
    return;
  }

  // If DoLookupIteration didn't send any RPCs, this will hit -1.
  BOOST_ASSERT(lookup_args->rpcs_in_flight_for_current_iteration >= -1);

  // If we should stop early (found value, or found single contact), do so.
  if (AbortLookup(result, values_and_signatures, contacts, cached_copy_holder,
                  peer, second_node, lookup_args))
    return;

  // Handle result if RPC was successful.
  auto shortlist_upper_bound(lookup_args->lookup_contacts.begin());
  if (FindResultError(result)) {
    shortlist_upper_bound = GetShortlistUpperBound(lookup_args);
  } else {
    (*this_peer).second.rpc_state = ContactInfo::kRepliedOK;
    OrderedContacts close_contacts(CreateOrderedContacts(contacts.begin(),
        contacts.end(), lookup_args->kTarget));
    RemoveDownlistedContacts(lookup_args, this_peer, &close_contacts);
    shortlist_upper_bound = InsertCloseContacts(close_contacts, lookup_args,
                                                this_peer);
  }

  // Check to see if the lookup phase and/or iteration is now finished.
  bool iteration_complete(false);
  int shortlist_ok_count(0);
  AssessLookupState(lookup_args, shortlist_upper_bound, &iteration_complete,
                    &shortlist_ok_count);

  // If the lookup phase is marked complete, but we still have <
  // kNumContactsRequested then try to get more contacts from the local routing
  // table.
  if (lookup_args->lookup_phase_complete &&
      shortlist_ok_count != lookup_args->kNumContactsRequested) {
    std::vector<Contact> close_nodes, excludes;
    excludes.reserve(shortlist_ok_count + lookup_args->downlist.size());
    auto shortlist_itr(lookup_args->lookup_contacts.begin());
    while (shortlist_itr != lookup_args->lookup_contacts.end())
      excludes.push_back((*shortlist_itr++).first);
    auto downlist_itr(lookup_args->downlist.begin());
    while (downlist_itr != lookup_args->downlist.end())
      excludes.push_back((*downlist_itr++).first);
    routing_table_->GetCloseContacts(lookup_args->kTarget, k_, excludes,
                                     &close_nodes);
    if (!close_nodes.empty()) {
      OrderedContacts close_contacts(
          CreateOrderedContacts(close_nodes.begin(), close_nodes.end(),
                                lookup_args->kTarget));
      shortlist_upper_bound =
          InsertCloseContacts(close_contacts, lookup_args,
                              lookup_args->lookup_contacts.end());
      lookup_args->lookup_phase_complete = false;
    } else {
      DLOG(WARNING) << DebugId(contact_) << ": Lookup is returning only "
                    << shortlist_ok_count << " contacts (k is " << k_ << ").";
    }
  }

  // If the lookup phase is still not finished, set cache candidate and start
  // next iteration if due.
  if (!lookup_args->lookup_phase_complete) {
    if (!FindResultError(result))
      lookup_args->cache_candidate = (*this_peer).first;
    if (iteration_complete)
      DoLookupIteration(lookup_args);
    return;
  }

  HandleCompletedLookup(lookup_args, shortlist_upper_bound, shortlist_ok_count);

  // If this is the last lookup callback, send the downlist notifications out.
  if (lookup_args->total_lookup_rpcs_in_flight == 0)
    SendDownlist(lookup_args->downlist);
}

bool NodeImpl::AbortLookup(
    int result,
    const std::vector<ValueAndSignature> &values_and_signatures,
    const std::vector<Contact> &contacts,
    const Contact &cached_copy_holder,
    const Contact &peer,
    bool second_node,
    LookupArgsPtr lookup_args) {
  if (lookup_args->kOperationType == LookupArgs::kFindValue) {
    // If the value was returned, or the peer claimed to have the value cached
    // outside of kademlia, we're finished with the lookup.
    if (result == kSuccess || result == kFoundCachedCopyHolder ||
        second_node) {
#ifdef DEBUG
      if (second_node) {
        BOOST_ASSERT(values_and_signatures.empty() && contacts.empty() &&
                     cached_copy_holder == Contact());
      } else {
        BOOST_ASSERT(!values_and_signatures.empty() ||
                     cached_copy_holder == peer);
      }
#endif
      FindValueReturns find_value_returns(result, values_and_signatures,
                                          contacts, cached_copy_holder,
                                          lookup_args->cache_candidate);
      lookup_args->lookup_phase_complete = true;
      std::static_pointer_cast<FindValueArgs>(lookup_args)->callback(
          find_value_returns);
      // TODO(Fraser#5#): 2011-08-16 - Send value to cache_candidate here.
//      if (std::static_pointer_cast<FindValueArgs>(lookup_args)->cache)
    }
    return lookup_args->lookup_phase_complete;
  } else if (lookup_args->kOperationType == LookupArgs::kGetContact) {
    // If the peer is the target, we're finished with the lookup, whether the
    // RPC timed out or not.
    if (peer.node_id() == lookup_args->kTarget) {
      lookup_args->lookup_phase_complete = true;
      if (result == kSuccess) {
        std::static_pointer_cast<GetContactArgs>(lookup_args)->callback(
            kSuccess, peer);
      } else {
        std::static_pointer_cast<GetContactArgs>(lookup_args)->callback(
            kFailedToGetContact, Contact());
      }
    }
    return lookup_args->lookup_phase_complete;
  }
  return false;
}

LookupContacts::iterator NodeImpl::GetShortlistUpperBound(
    LookupArgsPtr lookup_args) {
  uint16_t count(0);
  auto shortlist_upper_bound(lookup_args->lookup_contacts.begin());
  while (count != lookup_args->kNumContactsRequested &&
         shortlist_upper_bound != lookup_args->lookup_contacts.end()) {
    ++shortlist_upper_bound;
    ++count;
  }
  return shortlist_upper_bound;
}

void NodeImpl::RemoveDownlistedContacts(LookupArgsPtr lookup_args,
                                        LookupContacts::iterator this_peer,
                                        OrderedContacts *contacts) {
  auto downlist_itr(lookup_args->downlist.begin());
  auto contacts_itr(contacts->begin());
  while (downlist_itr != lookup_args->downlist.end() &&
         contacts_itr != contacts->end()) {
    if (contacts->key_comp()((*downlist_itr).first, *contacts_itr)) {
      ++downlist_itr;
    } else if (contacts->key_comp()(*contacts_itr, (*downlist_itr).first)) {
      ++contacts_itr;
    } else {
      (*downlist_itr++).second.providers.push_back((*this_peer).first);
      contacts->erase(contacts_itr++);
    }
  }
}

LookupContacts::iterator NodeImpl::InsertCloseContacts(
    const OrderedContacts &contacts,
    LookupArgsPtr lookup_args,
    LookupContacts::iterator this_peer) {
  if (!contacts.empty()) {
    auto existing_contacts_itr(lookup_args->lookup_contacts.begin());
    auto new_contacts_itr(contacts.begin());
    auto insertion_point(lookup_args->lookup_contacts.end());
    ContactInfo contact_info;
    if (existing_contacts_itr != lookup_args->lookup_contacts.end()) {
      if (this_peer != lookup_args->lookup_contacts.end())
        contact_info = ContactInfo((*this_peer).first);
      while ((new_contacts_itr != contacts.end()) &&
             (existing_contacts_itr != lookup_args->lookup_contacts.end())) {
        if (contacts.key_comp()((*existing_contacts_itr).first,
                                 *new_contacts_itr)) {
          insertion_point = existing_contacts_itr++;
        } else if (contacts.key_comp()(*new_contacts_itr,
                                       (*existing_contacts_itr).first)) {
          insertion_point = lookup_args->lookup_contacts.insert(
              insertion_point, std::make_pair(*new_contacts_itr++,
                                              contact_info));
        } else {
          insertion_point = existing_contacts_itr;
          if (this_peer != lookup_args->lookup_contacts.end()) {
            (*existing_contacts_itr++).second.providers.push_back(
                (*this_peer).first);
          }
          ++new_contacts_itr;
        }
      }
    }
    while (new_contacts_itr != contacts.end()) {
      insertion_point = lookup_args->lookup_contacts.insert(
          insertion_point, std::make_pair(*new_contacts_itr++,
                                          contact_info));
    }
  }
  auto itr = lookup_args->lookup_contacts.find(contact_);
  if (itr != lookup_args->lookup_contacts.end() && !client_only_node_) {
    (*itr).second.rpc_state = ContactInfo::kRepliedOK;
  }
  return GetShortlistUpperBound(lookup_args);
}

void NodeImpl::AssessLookupState(LookupArgsPtr lookup_args,
                                 LookupContacts::iterator shortlist_upper_bound,
                                 bool *iteration_complete,
                                 int *shortlist_ok_count) {
  *iteration_complete =
      (lookup_args->rpcs_in_flight_for_current_iteration <= kAlpha_ - kBeta_);

  lookup_args->lookup_phase_complete = true;
  auto itr(lookup_args->lookup_contacts.begin());
  while (itr != shortlist_upper_bound && lookup_args->lookup_phase_complete) {
    switch ((*itr).second.rpc_state) {
      case ContactInfo::kRepliedOK:
        ++(*shortlist_ok_count);
        break;
      case ContactInfo::kNotSent:
      case ContactInfo::kSent:
      case ContactInfo::kDelayed:
      default:
        lookup_args->lookup_phase_complete = false;
        break;
    }
    ++itr;
  }
}

void NodeImpl::HandleCompletedLookup(
    LookupArgsPtr lookup_args,
    LookupContacts::iterator closest_upper_bound,
    const int &closest_count) {
  switch (lookup_args->kOperationType) {
    case LookupArgs::kFindNodes:
    case LookupArgs::kFindValue: {
      auto itr(lookup_args->lookup_contacts.begin());
      std::vector<Contact> contacts;
      contacts.reserve(lookup_args->kNumContactsRequested);
      while (itr != closest_upper_bound) {
        BOOST_ASSERT((*itr).second.rpc_state == ContactInfo::kRepliedOK);
        contacts.push_back((*itr++).first);
      }
      if (lookup_args->kOperationType == LookupArgs::kFindNodes) {
        int result(contacts.empty() ? kFindNodesFailed : kSuccess);
        std::static_pointer_cast<FindNodesArgs>(lookup_args)->callback(result,
            contacts);
      } else {
        // We've already handled the case where the value or a cached copy
        // holder was found (in AbortLookup).
        int result(contacts.empty() ? kIterativeLookupFailed :
                   kFailedToFindValue);
        FindValueReturns find_value_returns(result,
                                            std::vector<ValueAndSignature>(),
                                            contacts, Contact(),
                                            lookup_args->cache_candidate);
        std::static_pointer_cast<FindValueArgs>(lookup_args)->callback(
            find_value_returns);
      }
      break;
    }
    case LookupArgs::kStore: {
      InitiateStorePhase(std::static_pointer_cast<StoreArgs>(lookup_args),
                         closest_upper_bound, closest_count);
      break;
    }
    case LookupArgs::kDelete: {
      InitiateDeletePhase(std::static_pointer_cast<DeleteArgs>(lookup_args),
                          closest_upper_bound, closest_count);
      break;
    }
    case LookupArgs::kUpdate: {
      InitiateUpdatePhase(std::static_pointer_cast<UpdateArgs>(lookup_args),
                          closest_upper_bound, closest_count);
      break;
    }
    case LookupArgs::kGetContact: {
      // We've already handled the case where the target contact was found (in
      // AbortLookup).
      std::static_pointer_cast<GetContactArgs>(lookup_args)->callback(
            kFailedToGetContact, Contact());
      break;
    }
    case LookupArgs::kStoreRefresh:
    case LookupArgs::kDeleteRefresh: {
      InitiateRefreshPhase(std::static_pointer_cast<RefreshArgs>(lookup_args),
                           closest_upper_bound, closest_count);
      break;
    }
    default: break;
  }
}

void NodeImpl::InitiateStorePhase(StoreArgsPtr store_args,
                                  LookupContacts::iterator closest_upper_bound,
                                  const int &closest_count) {
  if (closest_count < store_args->kSuccessThreshold) {
    if (closest_count == 0) {
      DLOG(ERROR) << DebugId(contact_) << ": Failed to get any contacts "
                  << "before store phase.";
      store_args->callback(kIterativeLookupFailed);
    } else {
      DLOG(ERROR) << DebugId(contact_) << ": Failed to get enough contacts "
                  << "to initiate store.";
      store_args->callback(kFoundTooFewNodes);
    }
    return;
  }
  auto itr(store_args->lookup_contacts.begin());
  while (itr != closest_upper_bound) {
    if (!client_only_node_ && ((*itr).first == contact_)) {
      HandleStoreToSelf(store_args);
    } else {
      rpcs_->Store(store_args->kTarget,
                   store_args->kValue,
                   store_args->kSignature,
                   store_args->kSecondsToLive,
                   store_args->private_key,
                   (*itr).first,
                   std::bind(&NodeImpl::StoreCallback, this, args::_1, args::_2,
                             (*itr).first, store_args));
      ++store_args->second_phase_rpcs_in_flight;
    }
    ++itr;
  }
}

void NodeImpl::InitiateDeletePhase(DeleteArgsPtr delete_args,
                                   LookupContacts::iterator closest_upper_bound,
                                   const int &closest_count) {
  if (closest_count < delete_args->kSuccessThreshold) {
    if (closest_count == 0) {
      DLOG(ERROR) << DebugId(contact_) << ": Failed to get any contacts "
                  << "before delete phase.";
      delete_args->callback(kIterativeLookupFailed);
    } else {
      DLOG(ERROR) << DebugId(contact_) << ": Failed to get enough contacts "
                  << "to initiate delete.";
      delete_args->callback(kFoundTooFewNodes);
    }
    return;
  }
  auto itr(delete_args->lookup_contacts.begin());
  while (itr != closest_upper_bound) {
    if (!client_only_node_ && ((*itr).first == contact_)) {
      HandleDeleteToSelf(delete_args);
    } else {
      rpcs_->Delete(delete_args->kTarget,
                    delete_args->kValue,
                    delete_args->kSignature,
                    delete_args->private_key,
                    (*itr).first,
                    std::bind(&NodeImpl::DeleteCallback, this, args::_1,
                              args::_2, (*itr).first, delete_args));
      ++delete_args->second_phase_rpcs_in_flight;
    }
    ++itr;
  }
}

void NodeImpl::InitiateUpdatePhase(UpdateArgsPtr update_args,
                                   LookupContacts::iterator closest_upper_bound,
                                   const int &closest_count) {
  if (closest_count < update_args->kSuccessThreshold) {
    if (closest_count == 0) {
      DLOG(ERROR) << DebugId(contact_) << ": Failed to get any contacts "
                  << "before update phase.";
      update_args->callback(kIterativeLookupFailed);
    } else {
      DLOG(ERROR) << DebugId(contact_) << ": Failed to get enough contacts "
                  << "to initiate update.";
      update_args->callback(kFoundTooFewNodes);
    }
    return;
  }
  auto itr(update_args->lookup_contacts.begin());
  while (itr != closest_upper_bound) {
    if (!client_only_node_ && ((*itr).first == contact_)) {
      HandleUpdateToSelf(update_args);
    } else {
      rpcs_->Store(update_args->kTarget,
                   update_args->kNewValue,
                   update_args->kNewSignature,
                   update_args->kSecondsToLive,
                   update_args->private_key,
                   (*itr).first,
                   std::bind(&NodeImpl::UpdateCallback, this, args::_1,
                             args::_2, (*itr).first, update_args));
      ++update_args->store_rpcs_in_flight;
      // Increment second_phase_rpcs_in_flight (representing the subsequent
      // Delete RPC) to avoid the DeleteCallback finishing early.  This assumes
      // the Store RPC will succeed - if it fails, we need to decrement
      // second_phase_rpcs_in_flight.
      ++update_args->second_phase_rpcs_in_flight;
    }
    ++itr;
  }
}

void NodeImpl::InitiateRefreshPhase(
    RefreshArgsPtr refresh_args,
    LookupContacts::iterator closest_upper_bound,
    const int &closest_count) {
  if (closest_count == 0) {
    DLOG(ERROR) << DebugId(contact_) << ": Failed to get any contacts "
                << "before refresh phase.";
    return;
  }
  auto itr(refresh_args->lookup_contacts.begin());
  bool this_node_within_closest(false);
  while (itr != closest_upper_bound) {
    if (!client_only_node_ && ((*itr).first == contact_)) {
      this_node_within_closest = true;
    } else {
      if (refresh_args->kOperationType == LookupArgs::kStoreRefresh) {
        rpcs_->StoreRefresh(refresh_args->kSerialisedRequest,
                            refresh_args->kSerialisedRequestSignature,
                            refresh_args->private_key, (*itr).first,
                            std::bind(&NodeImpl::HandleRpcCallback, this,
                                      (*itr).first, args::_1, args::_2));
      } else {
        rpcs_->DeleteRefresh(refresh_args->kSerialisedRequest,
                             refresh_args->kSerialisedRequestSignature,
                             refresh_args->private_key, (*itr).first,
                             std::bind(&NodeImpl::HandleRpcCallback, this,
                                       (*itr).first, args::_1, args::_2));
      }
    }
    ++itr;
  }
  if (!this_node_within_closest) {
    // TODO(Fraser#5#): 2011-09-02 - Remove k,v from data_store_, or move it to
    //                               a cache store.
  }
}

void NodeImpl::HandleStoreToSelf(StoreArgsPtr store_args) {
  // Check this node signed other values under same key in datastore
  ++store_args->second_phase_rpcs_in_flight;
  KeyValueSignature key_value_signature(store_args->kTarget.String(),
                                        store_args->kValue,
                                        store_args->kSignature);
  if (data_store_->DifferentSigner(key_value_signature,
                                   contact_.public_key())) {
    DLOG(WARNING) << DebugId(contact_) << ": Can't store to self - different "
                  << "signing key used to store under Kad key.";
    HandleSecondPhaseCallback<StoreArgsPtr>(kValueAlreadyExists, store_args);
    return;
  }

  // Check the signature validates with this node's public key
  if (!validate_functor_(store_args->kValue,
                         store_args->kSignature,
                         contact_.public_key())) {
    DLOG(ERROR) << DebugId(contact_) << ": Failed to validate Store request "
                << "for kademlia value";
    HandleSecondPhaseCallback<StoreArgsPtr>(kGeneralError, store_args);
    return;
  }

  // Store the value
  RequestAndSignature store_request_and_signature(
      rpcs_->MakeStoreRequestAndSignature(store_args->kTarget,
                                          store_args->kValue,
                                          store_args->kSignature,
                                          store_args->kSecondsToLive,
                                          store_args->private_key));
  int result(data_store_->StoreValue(key_value_signature,
                                     store_args->kSecondsToLive,
                                     store_request_and_signature,
                                     false));
  if (result == kSuccess) {
    HandleSecondPhaseCallback<StoreArgsPtr>(kSuccess, store_args);
  } else {
    DLOG(ERROR) << DebugId(contact_) << ": Failed to store value: " << result;
    HandleSecondPhaseCallback<StoreArgsPtr>(kGeneralError, store_args);
  }
}

void NodeImpl::HandleDeleteToSelf(DeleteArgsPtr delete_args) {
  ++delete_args->second_phase_rpcs_in_flight;

  if (!data_store_->HasKey(delete_args->kTarget.String())) {
    HandleSecondPhaseCallback<DeleteArgsPtr>(kSuccess, delete_args);
    return;
  }

  // Check this node signed other values under same key in datastore
  KeyValueSignature key_value_signature(delete_args->kTarget.String(),
                                        delete_args->kValue,
                                        delete_args->kSignature);
  if (data_store_->DifferentSigner(key_value_signature,
                                   contact_.public_key())) {
    DLOG(WARNING) << DebugId(contact_) << ": Can't delete to self - different "
                  << "signing key used to store under Kad key.";
    HandleSecondPhaseCallback<DeleteArgsPtr>(kGeneralError, delete_args);
    return;
  }

  // Check the signature validates with this node's public key
  if (!validate_functor_(delete_args->kValue,
                         delete_args->kSignature,
                         contact_.public_key())) {
    DLOG(ERROR) << DebugId(contact_) << ": Failed to validate Delete request "
                << "for kademlia value";
    HandleSecondPhaseCallback<DeleteArgsPtr>(kGeneralError, delete_args);
    return;
  }

  // Delete the value
  RequestAndSignature delete_request_and_signature(
      rpcs_->MakeDeleteRequestAndSignature(delete_args->kTarget,
                                           delete_args->kValue,
                                           delete_args->kSignature,
                                           delete_args->private_key));
  bool result(data_store_->DeleteValue(key_value_signature,
                                       delete_request_and_signature, false));
  if (result) {
    HandleSecondPhaseCallback<DeleteArgsPtr>(kSuccess, delete_args);
  } else {
    DLOG(ERROR) << DebugId(contact_) << ": Failed to delete value";
    HandleSecondPhaseCallback<DeleteArgsPtr>(kGeneralError, delete_args);
  }
}

void NodeImpl::HandleUpdateToSelf(UpdateArgsPtr update_args) {
  // Check this node signed other values under same key in datastore
  ++update_args->second_phase_rpcs_in_flight;
  KeyValueSignature new_key_value_signature(update_args->kTarget.String(),
                                            update_args->kNewValue,
                                            update_args->kNewSignature);
  if (data_store_->DifferentSigner(new_key_value_signature,
                                   contact_.public_key())) {
    DLOG(WARNING) << DebugId(contact_) << ": Can't update to self - different "
                  << "signing key used to store under Kad key.";
    HandleSecondPhaseCallback<UpdateArgsPtr>(kGeneralError, update_args);
    return;
  }

  // Check the new signature validates with this node's public key
  if (!validate_functor_(update_args->kNewValue,
                         update_args->kNewSignature,
                         contact_.public_key())) {
    DLOG(ERROR) << DebugId(contact_) << ": Failed to validate Update new "
                << "request for kademlia value";
    HandleSecondPhaseCallback<UpdateArgsPtr>(kGeneralError, update_args);
    return;
  }

  // Store the value
  RequestAndSignature store_request_and_signature(
      rpcs_->MakeStoreRequestAndSignature(update_args->kTarget,
                                          update_args->kNewValue,
                                          update_args->kNewSignature,
                                          update_args->kSecondsToLive,
                                          update_args->private_key));
  int result(data_store_->StoreValue(new_key_value_signature,
                                     update_args->kSecondsToLive,
                                     store_request_and_signature,
                                     false));
  if (result != kSuccess) {
    DLOG(ERROR) << DebugId(contact_) << ": Failed to store value: " << result;
    HandleSecondPhaseCallback<UpdateArgsPtr>(kGeneralError, update_args);
    return;
  }
  ++update_args->store_successes;

  if (update_args->kOldValue == update_args->kNewValue) {
    HandleSecondPhaseCallback<UpdateArgsPtr>(kSuccess, update_args);
    return;
  }

  // Check the old signature validates with this node's public key
  if (!validate_functor_(update_args->kOldValue,
                         update_args->kOldSignature,
                         contact_.public_key())) {
    DLOG(ERROR) << DebugId(contact_) << ": Failed to validate Update old "
                << "request for kademlia value";
    HandleSecondPhaseCallback<UpdateArgsPtr>(kGeneralError, update_args);
    return;
  }

  // Delete the value
  KeyValueSignature old_key_value_signature(update_args->kTarget.String(),
                                            update_args->kOldValue,
                                            update_args->kOldSignature);
  RequestAndSignature delete_request_and_signature(
      rpcs_->MakeDeleteRequestAndSignature(update_args->kTarget,
                                           update_args->kOldValue,
                                           update_args->kOldSignature,
                                           update_args->private_key));
  if (data_store_->DeleteValue(old_key_value_signature,
                               delete_request_and_signature, false)) {
    HandleSecondPhaseCallback<UpdateArgsPtr>(kSuccess, update_args);
  } else {
    DLOG(ERROR) << DebugId(contact_) << ": Failed to delete value";
    HandleSecondPhaseCallback<UpdateArgsPtr>(kGeneralError, update_args);
  }
}

void NodeImpl::StoreCallback(RankInfoPtr rank_info,
                             int result,
                             Contact peer,
                             StoreArgsPtr store_args) {
  AsyncHandleRpcCallback(peer, rank_info, result);
  boost::mutex::scoped_lock lock(store_args->mutex);
  HandleSecondPhaseCallback<StoreArgsPtr>(result, store_args);
  // If this is the last RPC, and the overall store failed, delete the value
  if (store_args->second_phase_rpcs_in_flight == 0 &&
      store_args->successes < store_args->kSuccessThreshold) {
    auto itr(store_args->lookup_contacts.begin());
    uint16_t count(0);
    while (itr != store_args->lookup_contacts.end() &&
           count != store_args->kNumContactsRequested) {
      if (!client_only_node_ && ((*itr).first == contact_)) {
        // Handle deleting from self
        KeyValueSignature key_value_signature(store_args->kTarget.String(),
                                              store_args->kValue,
                                              store_args->kSignature);
        RequestAndSignature delete_request_and_signature(
            rpcs_->MakeDeleteRequestAndSignature(store_args->kTarget,
                                                 store_args->kValue,
                                                 store_args->kSignature,
                                                 store_args->private_key));
        if (!data_store_->DeleteValue(key_value_signature,
                                      delete_request_and_signature, false)) {
          DLOG(WARNING) << DebugId(contact_) << ": Failed to delete value "
                        << "from self after bad store.";
        }
      } else {
        rpcs_->Delete(store_args->kTarget,
                      store_args->kValue,
                      store_args->kSignature,
                      store_args->private_key,
                      (*itr).first,
                      std::bind(&NodeImpl::HandleRpcCallback, this,
                                (*itr).first, args::_1, args::_2));
      }
      ++itr;
      ++count;
    }
  }
}

void NodeImpl::DeleteCallback(RankInfoPtr rank_info,
                              int result,
                              Contact peer,
                              LookupArgsPtr args) {
  AsyncHandleRpcCallback(peer, rank_info, result);
  boost::mutex::scoped_lock lock(args->mutex);
  if (args->kOperationType == LookupArgs::kDelete) {
    HandleSecondPhaseCallback<DeleteArgsPtr>(result,
        std::static_pointer_cast<DeleteArgs>(args));
  } else {
    HandleSecondPhaseCallback<UpdateArgsPtr>(result,
        std::static_pointer_cast<UpdateArgs>(args));
  }
  // TODO(Fraser#5#): 2011-08-16 - Decide if we want to try to re-store the
  //                  if the delete operation failed.  The problem is that we
  //                  don't have the outstanding TTL available here.
}

void NodeImpl::UpdateCallback(RankInfoPtr rank_info,
                              int result,
                              Contact peer,
                              UpdateArgsPtr update_args) {
  AsyncHandleRpcCallback(peer, rank_info, result);
  boost::mutex::scoped_lock lock(update_args->mutex);
  --update_args->store_rpcs_in_flight;
  BOOST_ASSERT(update_args->store_rpcs_in_flight >= 0);

  if (result == kSuccess && update_args->kSuccessThreshold <=
      update_args->store_successes + update_args->store_rpcs_in_flight) {
    ++update_args->store_successes;
    if (update_args->kOldValue != update_args->kNewValue)
      rpcs_->Delete(update_args->kTarget,
                    update_args->kOldValue,
                    update_args->kOldSignature,
                    update_args->private_key,
                    peer,
                    std::bind(&NodeImpl::DeleteCallback, this, args::_1,
                              args::_2, peer, update_args));
    else
      HandleSecondPhaseCallback<UpdateArgsPtr>(result,
          std::static_pointer_cast<UpdateArgs>(update_args));
  } else {
    // Decrement second_phase_rpcs_in_flight (representing the subsequent Delete
    // RPC) to avoid the DeleteCallback finishing early.
    --update_args->second_phase_rpcs_in_flight;
    BOOST_ASSERT(update_args->second_phase_rpcs_in_flight >= 0);
    if (update_args->kSuccessThreshold ==
        update_args->store_successes + update_args->store_rpcs_in_flight + 1) {
      update_args->callback(kUpdateTooFewNodes);
    }
  }
}

template <typename T>
void NodeImpl::HandleSecondPhaseCallback(int result, T args) {
  --args->second_phase_rpcs_in_flight;
  BOOST_ASSERT(args->second_phase_rpcs_in_flight >= 0);
  if (result == kSuccess) {
    ++args->successes;
    if (args->successes == args->kSuccessThreshold)
      args->callback(kSuccess);
  } else {
    if (args->kSuccessThreshold ==
        args->successes + args->second_phase_rpcs_in_flight + 1) {
      switch (args->kOperationType) {
        case LookupArgs::kStore:
          args->callback(kStoreTooFewNodes);
          break;
        case LookupArgs::kDelete:
          args->callback(kDeleteTooFewNodes);
          break;
        case LookupArgs::kUpdate:
          args->callback(kUpdateTooFewNodes);
          break;
        default:
          break;
      }
    }
  }
}

void NodeImpl::SendDownlist(const Downlist &downlist) {
  // Convert map of <down_contact, vector<providers>> to
  // map<provider, vector<down_ids>>.
  std::map<Contact, std::vector<NodeId>> downlist_by_provider;
  auto downlist_itr(downlist.begin());
  while (downlist_itr != downlist.end()) {
    auto provider_itr((*downlist_itr).second.providers.begin());
    while (provider_itr != (*downlist_itr).second.providers.end()) {
      auto insert_result(downlist_by_provider.insert(std::make_pair(
          *provider_itr,
          std::vector<NodeId>(1, (*downlist_itr).first.node_id()))));
      if (!insert_result.second) {
        (insert_result.first)->second.push_back(
            (*downlist_itr).first.node_id());
      }
      ++provider_itr;
    }
    ++downlist_itr;
  }
  // Send RPCs
  auto itr(downlist_by_provider.begin());
  while (joined_ && itr != downlist_by_provider.end()) {
    rpcs_->Downlist((*itr).second, default_private_key_, (*itr).first);
    ++itr;
  }
}

void NodeImpl::RefreshDataStore(const boost::system::error_code &error_code) {
  if (error_code) {
    if (error_code != boost::asio::error::operation_aborted) {
      DLOG(ERROR) << DebugId(contact_) << ": DataStore refresh timer error: "
                  << error_code.message();
    } else {
      return;
    }
  }
  if (!joined_)
    return;
  std::vector<KeyValueTuple> key_value_tuples;
  data_store_->Refresh(&key_value_tuples);
  std::for_each(key_value_tuples.begin(), key_value_tuples.end(),
                std::bind(&NodeImpl::RefreshData, this, args::_1));
  refresh_data_store_timer_.expires_at(refresh_data_store_timer_.expires_at() +
                                       kDataStoreCheckInterval_);
  refresh_data_store_timer_.async_wait(std::bind(&NodeImpl::RefreshDataStore,
                                                 this, args::_1));
}

void NodeImpl::RefreshData(const KeyValueTuple &key_value_tuple) {
  OrderedContacts close_contacts(
      GetClosestContactsLocally(Key(key_value_tuple.key()), k_));
  LookupArgs::OperationType op_type(key_value_tuple.deleted ?
                                    LookupArgs::kDeleteRefresh :
                                    LookupArgs::kStoreRefresh);
  RefreshArgsPtr refresh_args(new RefreshArgs(op_type,
      NodeId(key_value_tuple.key()), k_, close_contacts, default_private_key_,
      key_value_tuple.request_and_signature.first,
      key_value_tuple.request_and_signature.second));
  StartLookup(refresh_args);
}

bool NodeImpl::NodeContacted(const int &code) {
  switch (code) {
    case transport::kError:
    case transport::kSendFailure:
    case transport::kSendTimeout:
    case transport::kSendStalled:
    case kIterativeLookupFailed:
      return false;
    default:
      return true;
  }
}

void NodeImpl::PingOldestContact(const Contact &oldest_contact,
                                 const Contact &replacement_contact,
                                 RankInfoPtr replacement_rank_info) {
  rpcs_->Ping(default_private_key_,
              oldest_contact,
              std::bind(&NodeImpl::PingOldestContactCallback, this,
                        oldest_contact, args::_1, args::_2, replacement_contact,
                        replacement_rank_info));
}

void NodeImpl::PingOldestContactCallback(Contact oldest_contact,
                                         RankInfoPtr oldest_rank_info,
                                         const int &result,
                                         Contact replacement_contact,
                                         RankInfoPtr replacement_rank_info) {
  HandleRpcCallback(oldest_contact, oldest_rank_info, result);
  if (result != kSuccess) {
    // Try to add the new contact again in case the oldest was removed
    routing_table_->AddContact(replacement_contact, replacement_rank_info);
    routing_table_->SetValidated(replacement_contact.node_id(), true);
  }
}

void NodeImpl::ConnectPingOldestContact() {
  if (ping_oldest_contact_ == boost::signals2::connection()) {
    ping_oldest_contact_ =
        routing_table_->ping_oldest_contact()->connect(
            std::bind(&NodeImpl::PingOldestContact, this, args::_1, args::_2,
                      args::_3));
  }
}

void NodeImpl::ValidateContact(const Contact &contact) {
  asymm::GetPublicKeyAndValidationCallback callback(
      std::bind(&NodeImpl::ValidateContactCallback, this, contact, args::_1,
                args::_2));
  contact_validation_getter_(contact.public_key_id(), callback);
}

void NodeImpl::ValidateContactCallback(
    Contact contact,
    asymm::PublicKey public_key,
    asymm::ValidationToken public_key_validation) {
  bool valid = contact_validator_(contact.public_key_id(),
                                  public_key, public_key_validation);
  routing_table_->SetValidated(contact.node_id(), valid);
}

void NodeImpl::ConnectValidateContact() {
  if (validate_contact_ == boost::signals2::connection()) {
    validate_contact_ = routing_table_->validate_contact()->connect(
        std::bind(&NodeImpl::ValidateContact, this, args::_1));
  }
}

void NodeImpl::PingDownContact(const Contact &down_contact) {
  rpcs_->Ping(default_private_key_,
              down_contact,
              std::bind(&NodeImpl::PingDownContactCallback, this,
                        down_contact, args::_1, args::_2));
}

void NodeImpl::PingDownContactCallback(Contact down_contact,
                                       RankInfoPtr rank_info,
                                       const int &result) {
  if (result != kSuccess) {
    // Increment failed RPC count until down contact is removed from the routing
    // table
    for (int i = 0, result = 0;
        result != kFailedToFindContact && i < kFailedRpcTolerance + 1; ++i)
      result = routing_table_->IncrementFailedRpcCount(down_contact.node_id());
  } else {
    // Add the contact again to update its last_seen to now
    routing_table_->AddContact(down_contact, rank_info);
  }
}

void NodeImpl::ConnectPingDownContact() {
  if (ping_down_contact_ == boost::signals2::connection()) {
    ping_down_contact_ = routing_table_->ping_down_contact()->connect(
        std::bind(&NodeImpl::PingDownContact, this, args::_1));
  }
}

void NodeImpl::HandleRpcCallback(const Contact &contact,
                                 RankInfoPtr rank_info,
                                 const int &result) {
  int routing_table_result(kSuccess);
  if (!FindResultError(result)) {
    // Add the contact to update its last_seen to now
    routing_table_result = routing_table_->AddContact(contact, rank_info);
  } else {
    routing_table_result =
        routing_table_->IncrementFailedRpcCount(contact.node_id());
  }
#ifdef DEBUG
  if (routing_table_result != kSuccess)
    DLOG(INFO) << DebugId(contact_) << ": Failed to update routing table for "
               << "contact " << DebugId(contact) << ".  RPC result: " << result
               << "  Update result: " << routing_table_result;
#endif
}

void NodeImpl::AsyncHandleRpcCallback(const Contact &contact,
                                      RankInfoPtr rank_info,
                                      const int &result) {
  asio_service_.post(std::bind(&NodeImpl::HandleRpcCallback, this, contact,
                               rank_info, result));
}

void NodeImpl::set_check_cache_functor(
    const CheckCacheFunctor &check_cache_functor) {
  boost::mutex::scoped_lock lock(join_mutex_);
  check_cache_functor_ = check_cache_functor;
  if (service_)
    service_->set_check_cache_functor(check_cache_functor);
}


}  // namespace dht
}  // namespace maidsafe

Added wiki_references/2017/software/MaidSafe_net/src_from_GitHub/the_repository_clones/MaidSafe-DHT/src/maidsafe/dht/node_impl.h version [8e46bc65b6].













































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
/* Copyright (c) 2009 maidsafe.net limited
All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

    * Redistributions of source code must retain the above copyright notice,
    this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright notice,
    this list of conditions and the following disclaimer in the documentation
    and/or other materials provided with the distribution.
    * Neither the name of the maidsafe.net limited nor the names of its
    contributors may be used to endorse or promote products derived from this
    software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#ifndef MAIDSAFE_DHT_NODE_IMPL_H_
#define MAIDSAFE_DHT_NODE_IMPL_H_

#include <cstdint>
#include <memory>
#include <string>
#include <vector>

#include "boost/asio/io_service.hpp"
#include "boost/asio/deadline_timer.hpp"
#include "boost/date_time/posix_time/posix_time_types.hpp"
#include "boost/signals2/connection.hpp"
#include "boost/thread/mutex.hpp"

#include "maidsafe/dht/node_impl_structs.h"
#include "maidsafe/dht/config.h"
#include "maidsafe/dht/node-api.h"
#include "maidsafe/dht/contact.h"
#include "maidsafe/dht/node_container.h"


namespace bptime = boost::posix_time;

namespace maidsafe {

namespace dht {

class DataStore;
struct KeyValueTuple;
class Service;
class RoutingTable;
template <typename T>
class Rpcs;

namespace test {
class NodeImplTest;
class MockNodeImplTest;
class MockNodeImplTest_BEH_ValidateContact_Test;
class MockNodeImplTest_BEH_PingOldestContact_Test;
class MockNodeImplTest_BEH_Join_Test;
class MockNodeImplTest_BEH_Getters_Test;
class MockNodeImplTest_BEH_FindNodes_Test;
class MockNodeImplTest_BEH_FindValue_Test;
class MockNodeImplTest_BEH_AssessLookupState_Test;
class MockNodeImplTest_BEH_RemoveDownlistedContacts_Test;
class MockNodeImplTest_BEH_InsertCloseContacts_Test;
class NodeImplTest_FUNC_StoreRefreshInvalidSigner_Test;
}  // namespace test

typedef std::function<void(RankInfoPtr, const int&)> StoreRefreshFunctor;

class NodeImpl {
 public:
  NodeImpl(boost::asio::io_service &asio_service,             // NOLINT (Fraser)
           TransportPtr listening_transport,
           MessageHandlerPtr message_handler,
           KeyPairPtr default_asym_key_pair,
           bool client_only_node,
           const uint16_t &k,
           const uint16_t &alpha,
           const uint16_t &beta,
           const bptime::time_duration &mean_refresh_interval);

  // virtual destructor to allow tests to use a derived NodeImpl and befriend it
  // rather than polluting this with friend tests.
  virtual ~NodeImpl();

  void Join(const NodeId &node_id,
            std::vector<Contact> bootstrap_contacts,
            JoinFunctor callback);

  void Leave(std::vector<Contact> *bootstrap_contacts);

  /** Function to STORE data to the Kademlia network.
   *  @param[in] Key The key to find
   *  @param[in] value The value to store.
   *  @param[in] signature The signature to store.
   *  @param[in] ttl The ttl for the new data.
   *  @param[in] private_key The private key to pass further.
   *  @param[in] callback The callback to report the results. */
  void Store(const Key &key,
             const std::string &value,
             const std::string &signature,
             const bptime::time_duration &ttl,
             PrivateKeyPtr private_key,
             StoreFunctor callback);

  /** Function to DELETE the content of a <key, value> in the Kademlia network.
   *  The operation will delete the original one then store the new one.
   *  @param[in] Key The key to find
   *  @param[in] value The value to delete.
   *  @param[in] signature The signature to delete.
   *  @param[in] private_key The private key to pass further.
   *  @param[in] callback The callback to report the results. */
  void Delete(const Key &key,
              const std::string &value,
              const std::string &signature,
              PrivateKeyPtr private_key,
              DeleteFunctor callback);

  /** Function to UPDATE the content of a <key, value> in the Kademlia network.
   *  The operation will delete the original one then store the new one.
   *  @param[in] Key The key to find
   *  @param[in] new_value The new_value to store.
   *  @param[in] new_signature The new_signature to store.
   *  @param[in] old_value The old_value to delete.
   *  @param[in] old_signature The old_signature to delete.
   *  @param[in] ttl The ttl for the new data.
   *  @param[in] private_key The private key to pass further.
   *  @param[in] callback The callback to report the results. */
  void Update(const Key &key,
              const std::string &new_value,
              const std::string &new_signature,
              const std::string &old_value,
              const std::string &old_signature,
              const bptime::time_duration &ttl,
              PrivateKeyPtr private_key,
              UpdateFunctor callback);

  /** Function to FIND VALUES of the Key from the Kademlia network.
   *  @param[in] Key The key to find
   *  @param[in] private_key The private key to pass further.
   *  @param[in] callback The callback to report the results.
   *  @param[in] extra_contacts The number of additional to k contacts to
   *  return.
   *  @param[in] cache Whether to cache the value(s) if found. */
  void FindValue(const Key &key,
                 PrivateKeyPtr private_key,
                 FindValueFunctor callback,
                 const uint16_t &extra_contacts = 0,
                 bool cache = true);

  /** Function to FIND k-closest NODES to the Key from the Kademlia network.
   *  @param[in] Key The key to locate
   *  @param[in] callback The callback to report the results.
   *  @param[in] extra_contacts The number of additional to k contacts to
   *  return. */
  void FindNodes(const Key &key,
                 FindNodesFunctor callback,
                 const uint16_t &extra_contacts = 0);

  /** Function to get a contact info from the Kademlia network.
   *  @param[in] node_id The node_id to locate
   *  @param[in] callback The callback to report the results. */
  void GetContact(const NodeId &node_id, GetContactFunctor callback);

  // Setter for the functor which will be called by Node and Service to retrieve
  // the public key and public key validation token for a given contact.
  void SetContactValidationGetter(
      asymm::GetPublicKeyAndValidationFunctor contact_validation_getter);

  // Setter for the functor which will be invoked in the callback of
  // contact_validation_getter above.  It will return true if the retrieved
  // public key validates correctly against the retrieved validation token.
  void SetContactValidator(asymm::ValidatePublicKeyFunctor contact_validator);

  // Setter for the functor which will be invoked for checking a signature
  // against a given public key.
  void SetValidate(asymm::ValidateFunctor validate_functor);

  /** Investigates the contact's online/offline status
   *  @param[in] contact the contact to be pinged
   *  @param[in] callback The callback to report the result. */
  void Ping(const Contact &contact, PingFunctor callback);

  /** Function to set the contact's last_seen to now.
   *  @param[in] contact The contact to set */
  void SetLastSeenToNow(const Contact &contact);

  /** Function to set the contact's last_seen to now.
   *  @param[in] contact The contact to set */
  void IncrementFailedRpcs(const Contact &contact);

  /** Function to update the contact's rank_info.
   *  @param[in] contact The contact to update
   *  @param[in] rank_info The rank info to update */
  void UpdateRankInfo(const Contact &contact, RankInfoPtr rank_info);

  /** Get the local RankInfo of the contact
   *  @param[in] contact The contact to find
   *  @return The localRankInfo of the contact */
  RankInfoPtr GetLocalRankInfo(const Contact &contact) const;

  /** Get all contacts in the routing table
   *  @param[out] contacts All contacts in the routing table */
  void GetAllContacts(std::vector<Contact> *contacts);

  /** Get Bootstrap contacts in the routing table
   *  @param[out] contacts Bootstrap contacts in the routing table */
  void GetBootstrapContacts(std::vector<Contact> *contacts);

  void set_check_cache_functor(const CheckCacheFunctor &check_cache_functor);

  Contact contact() const { return contact_; }

  bool joined() const { return joined_; }

  OnOnlineStatusChangePtr on_online_status_change() {
    return on_online_status_change_;
  }

  bool client_only_node() const { return client_only_node_; }

  uint16_t k() const { return k_; }

  friend class NodeContainer<maidsafe::dht::NodeImpl>;
  friend class test::NodeImplTest;
  friend class test::MockNodeImplTest;
  friend class test::MockNodeImplTest_BEH_ValidateContact_Test;
  friend class test::MockNodeImplTest_BEH_PingOldestContact_Test;
  friend class test::MockNodeImplTest_BEH_Join_Test;
  friend class test::MockNodeImplTest_BEH_Getters_Test;
  friend class test::MockNodeImplTest_BEH_FindNodes_Test;
  friend class test::MockNodeImplTest_BEH_FindValue_Test;
  friend class test::MockNodeImplTest_BEH_AssessLookupState_Test;
  friend class test::MockNodeImplTest_BEH_RemoveDownlistedContacts_Test;
  friend class test::MockNodeImplTest_BEH_InsertCloseContacts_Test;
  friend class test::NodeImplTest_FUNC_StoreRefreshInvalidSigner_Test;

 private:
  NodeImpl(const NodeImpl&);
  NodeImpl &operator=(const NodeImpl&);

  void JoinFindValueCallback(FindValueReturns find_value_returns,
                             std::vector<Contact> bootstrap_contacts,
                             const NodeId &node_id,
                             JoinFunctor callback,
                             bool none_reached);

  void JoinSucceeded(JoinFunctor callback);

  void JoinFailed(JoinFunctor callback, int result);

  template <typename T>
  void NotJoined(T callback);

  template <typename T>
  void FailedValidation(T callback);

  /** Returns the closest contacts to key from this node's routing table.  If
   *  this node is within the required closest, it is included in the result. */
  OrderedContacts GetClosestContactsLocally(const Key &key,
                                            const uint16_t &total_contacts);

  /** If signature is empty, it is set to the signature of value.
   *  Else returns kSuccess */
  int SignIfEmpty(const std::string &value,
                  PrivateKeyPtr private_key,
                  std::string *signature);

  /** Runs the FindValue callback for the case where this node has the value(s)
   *  locally (i.e. cached outside of kademlia or in data_store_). */
  void FoundValueLocally(const FindValueReturns &find_value_returns,
                         FindValueFunctor callback);

  /** Runs the GetContact callback for the case where it's this node's Contact
   *  which is the target. */
  void GetOwnContact(GetContactFunctor callback);

  /** Callback used if we hold the target's contact details in our own routing
   *  table - i.e. we only did a Ping rather than an iterative lookup. */
  void GetContactPingCallback(RankInfoPtr rank_info,
                              int result,
                              Contact peer,
                              GetContactFunctor callback);

  void PingCallback(RankInfoPtr rank_info,
                    int result,
                    Contact peer,
                    PingFunctor callback);

  void StartLookup(LookupArgsPtr lookup_args);

  /** Function to execute iterative rpc->findnode or findvalue requests.
   *  @param[in] find_args The arguments struct holding all shared info. */
  void DoLookupIteration(LookupArgsPtr lookup_args);

  /** Callback from the rpc->findvalue or findnodes requests.
   *  @param[in] rank_info rank info
   *  @param[in] result Indicator from the rpc. Any negative value shall be
   *  considered as the enquired contact got some problems.
   *  @param[in] values_and_signatures The values and signatures of the key.
   *  @param[in] contacts The closest contacts.
   *  @param[in] cached_copy_holder The cached copy holder's contact.
   *  @param[in] peer The Contact being queried.
   *  @param[in] lookup_args The arguments struct holding all shared info. */
  void IterativeFindCallback(
      RankInfoPtr rank_info,
      int result,
      const std::vector<ValueAndSignature> &values_and_signatures,
      const std::vector<Contact> &contacts,
      const Contact &cached_copy_holder,
      Contact peer,
      LookupArgsPtr lookup_args);

  bool AbortLookup(int result,
                   const std::vector<ValueAndSignature> &values_and_signatures,
                   const std::vector<Contact> &contacts,
                   const Contact &cached_copy_holder,
                   const Contact &peer,
                   bool second_node,
                   LookupArgsPtr lookup_args);

  LookupContacts::iterator GetShortlistUpperBound(LookupArgsPtr lookup_args);

  /** Moves any Contacts found in the downlist from "contacts" to the
   *  downlist */
  void RemoveDownlistedContacts(LookupArgsPtr lookup_args,
                                LookupContacts::iterator this_peer,
                                OrderedContacts *contacts);

  /** Adds "contacts" to the current lookup shortlist and return an iterator to
   *  the current (n+1)th closest where n is the number of contacts requested */
  LookupContacts::iterator InsertCloseContacts(
      const OrderedContacts &contacts,
      LookupArgsPtr lookup_args,
      LookupContacts::iterator this_peer);

  void AssessLookupState(LookupArgsPtr lookup_args,
                         LookupContacts::iterator shortlist_upper_bound,
                         bool *iteration_complete,
                         int *shortlist_ok_count);

  void HandleCompletedLookup(LookupArgsPtr lookup_args,
                             LookupContacts::iterator closest_upper_bound,
                             const int &closest_count);

  void InitiateStorePhase(StoreArgsPtr store_args,
                          LookupContacts::iterator closest_upper_bound,
                          const int &closest_count);

  void InitiateDeletePhase(DeleteArgsPtr delete_args,
                           LookupContacts::iterator closest_upper_bound,
                           const int &closest_count);

  void InitiateUpdatePhase(UpdateArgsPtr update_args,
                           LookupContacts::iterator closest_upper_bound,
                           const int &closest_count);

  void InitiateRefreshPhase(RefreshArgsPtr refresh_args,
                            LookupContacts::iterator closest_upper_bound,
                            const int &closest_count);

  void HandleStoreToSelf(StoreArgsPtr store_args);

  void HandleDeleteToSelf(DeleteArgsPtr delete_args);

  void HandleUpdateToSelf(UpdateArgsPtr update_args);

  /** Callback from the rpc->store requests, during the Store operation.
   *  @param[in] rank_info rank info
   *  @param[in] result Indicator from the rpc->store. Any negative value shall
   *  be considered as the enquired contact got some problems.
   *  @param[in] peer The Contact being queried.
   *  @param[in] store_args The arguments struct holding all shared info. */
  void StoreCallback(RankInfoPtr rank_info,
                     int result,
                     Contact peer,
                     StoreArgsPtr store_args);

  /** Callback from the rpc->delete requests. Need to calculate number of
   *  success and report back the final result.  Used by: Delete, Update
   *  @param[in] rank_info rank info
   *  @param[in] result Indicator from the rpc->delete. Any negative value shall
   *  be considered as the enquired contact got some problems.
   *  @param[in] peer The Contact being queried.
   *  @param[in] args The arguments struct holding all shared info */
  void DeleteCallback(RankInfoPtr rank_info,
                      int result,
                      Contact peer,
                      LookupArgsPtr args);

  /** Callback from the rpc->store requests, during the Update operation.
   *  @param[in] rank_info rank info
   *  @param[in] result Indicator from the rpc->store. Any negative value shall
   *  be considered as the enquired contact got some problems.
   *  @param[in] peer The Contact being queried.
   *  @param[in] update_args The arguments struct holding all shared info. */
  void UpdateCallback(RankInfoPtr rank_info,
                     int result,
                     Contact peer,
                     UpdateArgsPtr update_args);

  template <typename T>
  void HandleSecondPhaseCallback(int result, T args);

  void SendDownlist(const Downlist &downlist);

  void RefreshDataStore(const boost::system::error_code &error_code);

  void RefreshData(const KeyValueTuple &key_value_tuple);

  /** returns true if the code conveys that the node has not been reached
   *  @param[in] code  the code denoting the response type*/
  bool NodeContacted(const int &code);

  /** Function to be connected with the ping_oldest_contact signal in routing
   *  table. Will try to ping the report in oldest contact
   *  @param[in] oldest_contact The report in oldest_contact
   *  @param[in] replacement_contact The contact trying to replace the oldest
   *  @param[in] replacement_rank_info Rank info of the replacement contact */
  void PingOldestContact(const Contact &oldest_contact,
                         const Contact &replacement_contact,
                         RankInfoPtr replacement_rank_info);

  /** Callback Function of the PingOldestContact
   *  Will try to replace the oldest with the new one if no response from the
   *  oldest
   *  @param[in] oldest_contact The report in oldest_contact
   *  @param[in] oldest_rank_info Rank info of the oldest contact
   *  @param[in] result Result from the Ping. Any negative value indicates fail
   *  @param[in] replacement_contact The contact trying to replace the oldest
   *  @param[in] replacement_rank_info Rank info of the replacement contact */
  void PingOldestContactCallback(Contact oldest_contact,
                                 RankInfoPtr oldest_rank_info,
                                 const int &result,
                                 Contact replacement_contact,
                                 RankInfoPtr replacement_rank_info);

  /** Will connect the ping_oldest_contact signal in routing table to
   *  PingOldestContact if not already done. */
  void ConnectPingOldestContact();

  /** Function to be connected with the validate_contact signal in routing
   *  table. Will try to validate the contact
   *  @param[in] contact The contact needs to be validated */
  void ValidateContact(const Contact &contact);

  /** Callback Functionof the ValidateContact
   *  @param[in] contact The contact needs to be validated
   *  @param[in] public_key The public_key of the contact
   *  @param[in] public_key_validation The contact's public_key_validation */
  void ValidateContactCallback(Contact contact,
                               asymm::PublicKey public_key,
                               asymm::ValidationToken public_key_validation);

  /** Will connect the validate_contact signal in routing table to
   *  ValidateContact if not already done. */
  void ConnectValidateContact();

  /** Function to be connected with the ping_down_contact signal in routing
   *  table. Will try to ping the downlisted contact
   *  @param[in] down_contact The reported downlisted contact */
  void PingDownContact(const Contact &down_contact);

  /** Callback Function of the PingDownContact
   *  @param[in] down_contact The reported downlisted contact
   *  @param[in] rank_info Rank info of the reported downlisted contact
   *  @param[in] result Result from the Ping. Any negative value indicates
   *  failure */
  void PingDownContactCallback(Contact down_contact,
                               RankInfoPtr rank_info,
                               const int &result);

  /** Will connect the ping_down_contact signal in routing table to
   *  PingDownContact if not already done. */
  void ConnectPingDownContact();

  /** All RPCs should update the routing table for the given contact using this
   *  method */
  void HandleRpcCallback(const Contact &contact,
                         RankInfoPtr rank_info,
                         const int &result);

  /** Posts HandleRpcCallback to asio service */
  void AsyncHandleRpcCallback(const Contact &contact,
                              RankInfoPtr rank_info,
                              const int &result);

  boost::asio::io_service &asio_service_;
  TransportPtr listening_transport_;
  MessageHandlerPtr message_handler_;
  PublicKeyPtr default_public_key_;
  PrivateKeyPtr default_private_key_;
  OnOnlineStatusChangePtr on_online_status_change_;
  bool client_only_node_;
  /** Kademlia k parameter */
  const uint16_t k_;
  /** Kademlia alpha parameter to define how many contacts are to be queried
   *  per lookup iteration */
  const uint16_t kAlpha_;
  /** Kademlia beta parameter to define how many contacts are required to have
   *  responded in a lookup iteration before starting a new iteration */
  const uint16_t kBeta_;
  const bptime::seconds kMeanRefreshInterval_, kDataStoreCheckInterval_;
  std::shared_ptr<DataStore> data_store_;
  std::shared_ptr<Service> service_;
  std::shared_ptr<RoutingTable> routing_table_;
  std::shared_ptr<Rpcs<transport::TcpTransport>> rpcs_;
  asymm::GetPublicKeyAndValidationFunctor contact_validation_getter_;
  asymm::ValidatePublicKeyFunctor contact_validator_;
  asymm::ValidateFunctor validate_functor_;
  /** Own info of nodeid, ip and port */
  Contact contact_;
  bool joined_;
  boost::signals2::connection ping_oldest_contact_, validate_contact_,
                              ping_down_contact_;
  boost::asio::deadline_timer refresh_data_store_timer_;
  boost::mutex join_mutex_;
  CheckCacheFunctor check_cache_functor_;
};

}  // namespace dht

}  // namespace maidsafe

#endif  // MAIDSAFE_DHT_NODE_IMPL_H_

Added wiki_references/2017/software/MaidSafe_net/src_from_GitHub/the_repository_clones/MaidSafe-DHT/src/maidsafe/dht/node_impl_structs.h version [6769ab1f7e].















































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
/* Copyright (c) 2009 maidsafe.net limited
All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

    * Redistributions of source code must retain the above copyright notice,
    this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright notice,
    this list of conditions and the following disclaimer in the documentation
    and/or other materials provided with the distribution.
    * Neither the name of the maidsafe.net limited nor the names of its
    contributors may be used to endorse or promote products derived from this
    software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#ifndef MAIDSAFE_DHT_NODE_IMPL_STRUCTS_H_
#define MAIDSAFE_DHT_NODE_IMPL_STRUCTS_H_

#include <map>
#include <memory>
#include <string>
#include <vector>

#include "boost/thread/mutex.hpp"
#ifdef __MSVC__
#  pragma warning(push)
#  pragma warning(disable: 4244)
#endif
#include "boost/multi_index_container.hpp"
#include "boost/multi_index/composite_key.hpp"
#include "boost/multi_index/ordered_index.hpp"
#include "boost/multi_index/identity.hpp"
#include "boost/multi_index/member.hpp"
#ifdef __MSVC__
#  pragma warning(pop)
#endif

#include "maidsafe/dht/config.h"
#include "maidsafe/dht/contact.h"
#include "maidsafe/dht/node_id.h"
#include "maidsafe/dht/rpcs.h"
#include "maidsafe/dht/utils.h"

namespace maidsafe {

namespace dht {

struct ContactInfo {
  enum RpcState { kNotSent, kSent, kDelayed, kRepliedOK };
  ContactInfo() : providers(), rpc_state(kNotSent) {}
  explicit ContactInfo(const Contact &provider) : providers(1, provider),
                                                  rpc_state(kNotSent) {}
  std::vector<Contact> providers;
  RpcState rpc_state;
};

typedef std::map<Contact,
                 ContactInfo,
                 std::function<bool(const Contact&,  // NOLINT (Fraser)
                                    const Contact&)>> LookupContacts, Downlist;

struct LookupArgs {
  enum OperationType {
    kFindNodes,
    kFindValue,
    kStore,
    kDelete,
    kUpdate,
    kGetContact,
    kStoreRefresh,
    kDeleteRefresh
  };
  LookupArgs(OperationType operation_type,
             const NodeId &target,
             const OrderedContacts &close_contacts,
             const uint16_t &num_contacts_requested,
             PrivateKeyPtr priv_key)
      : lookup_contacts(std::bind(static_cast<bool(*)(const Contact&,  // NOLINT (Fraser)
            const Contact&, const NodeId&)>(&CloserToTarget),
            args::_1, args::_2, target)),
        downlist(std::bind(static_cast<bool(*)(const Contact&,  // NOLINT (Fraser)
                 const Contact&, const NodeId&)>(&CloserToTarget),
                 args::_1, args::_2, target)),
        cache_candidate(),
        mutex(),
        total_lookup_rpcs_in_flight(0),
        rpcs_in_flight_for_current_iteration(0),
        lookup_phase_complete(false),
        kOperationType(operation_type),
        kTarget(target),
        kNumContactsRequested(num_contacts_requested),
        private_key(priv_key) {
    auto insert_itr(lookup_contacts.end());
    for (auto it(close_contacts.begin()); it != close_contacts.end(); ++it) {
      insert_itr = lookup_contacts.insert(insert_itr,
                                          std::make_pair((*it), ContactInfo()));
    }
  }
  virtual ~LookupArgs() {}
  LookupContacts lookup_contacts;
  Downlist downlist;
  Contact cache_candidate;
  boost::mutex mutex;
  int total_lookup_rpcs_in_flight, rpcs_in_flight_for_current_iteration;
  bool lookup_phase_complete;
  const OperationType kOperationType;
  const NodeId kTarget;
  const uint16_t kNumContactsRequested;
  PrivateKeyPtr private_key;
};

struct FindNodesArgs : public LookupArgs {
  FindNodesArgs(const NodeId &target,
                const uint16_t &num_contacts_requested,
                const OrderedContacts &close_contacts,
                PrivateKeyPtr private_key,
                FindNodesFunctor callback_in)
      : LookupArgs(kFindNodes, target, close_contacts, num_contacts_requested,
                   private_key),
        callback(callback_in) {}
  FindNodesFunctor callback;
};

struct FindValueArgs : public LookupArgs {
  FindValueArgs(const NodeId &target,
                const uint16_t &num_contacts_requested,
                const OrderedContacts &close_contacts,
                bool cache_in,
                PrivateKeyPtr private_key,
                FindValueFunctor callback_in)
      : LookupArgs(kFindValue, target, close_contacts, num_contacts_requested,
                   private_key),
        cache(cache_in),
        callback(callback_in) {}
  bool cache;
  FindValueFunctor callback;
};

struct StoreArgs : public LookupArgs {
  StoreArgs(const NodeId &target,
            const uint16_t &num_contacts_requested,
            const OrderedContacts &close_contacts,
            const int &success_threshold,
            const std::string &value,
            const std::string &signature,
            const bptime::time_duration &time_to_live,
            PrivateKeyPtr private_key,
            StoreFunctor callback_in)
      : LookupArgs(kStore, target, close_contacts, num_contacts_requested,
                   private_key),
        kSuccessThreshold(success_threshold),
        second_phase_rpcs_in_flight(0),
        successes(0),
        kValue(value),
        kSignature(signature),
        kSecondsToLive(time_to_live.total_seconds()),
        callback(callback_in) {}
  const int kSuccessThreshold;
  int second_phase_rpcs_in_flight, successes;
  const std::string kValue, kSignature;
  const bptime::seconds kSecondsToLive;
  StoreFunctor callback;
};

struct DeleteArgs : public LookupArgs {
  DeleteArgs(const NodeId &target,
             const uint16_t &num_contacts_requested,
             const OrderedContacts &close_contacts,
             const int &success_threshold,
             const std::string &value,
             const std::string &signature,
             PrivateKeyPtr private_key,
             DeleteFunctor callback_in)
      : LookupArgs(kDelete, target, close_contacts, num_contacts_requested,
                   private_key),
        kSuccessThreshold(success_threshold),
        second_phase_rpcs_in_flight(0),
        successes(0),
        kValue(value),
        kSignature(signature),
        callback(callback_in) {}
  const int kSuccessThreshold;
  int second_phase_rpcs_in_flight, successes;
  const std::string kValue, kSignature;
  DeleteFunctor callback;
};

struct UpdateArgs : public LookupArgs {
  UpdateArgs(const NodeId &target,
             const uint16_t &num_contacts_requested,
             const OrderedContacts &close_contacts,
             const int &success_threshold,
             const std::string &old_value,
             const std::string &old_signature,
             const std::string &new_value,
             const std::string &new_signature,
             const bptime::time_duration &time_to_live,
             PrivateKeyPtr private_key,
             UpdateFunctor callback_in)
      : LookupArgs(kUpdate, target, close_contacts, num_contacts_requested,
                   private_key),
        kSuccessThreshold(success_threshold),
        store_rpcs_in_flight(0),
        store_successes(0),
        second_phase_rpcs_in_flight(0),
        successes(0),
        kOldValue(old_value),
        kOldSignature(old_signature),
        kNewValue(new_value),
        kNewSignature(new_signature),
        kSecondsToLive(time_to_live.total_seconds()),
        callback(callback_in) {}
  const int kSuccessThreshold;
  // store_rpcs_in_flight and store_successes relate to the Store part of the
  // second phase.  second_phase_rpcs_in_flight and successes relate to the
  // Delete part of the second phase.
  int store_rpcs_in_flight, store_successes, second_phase_rpcs_in_flight,
         successes;
  const std::string kOldValue, kOldSignature, kNewValue, kNewSignature;
  const bptime::seconds kSecondsToLive;
  UpdateFunctor callback;
};

struct GetContactArgs : public LookupArgs {
  GetContactArgs(const NodeId &target,
                 const uint16_t &num_contacts_requested,
                 const OrderedContacts &close_contacts,
                 PrivateKeyPtr private_key,
                 GetContactFunctor callback_in)
      : LookupArgs(kGetContact, target, close_contacts, num_contacts_requested,
                   private_key),
        callback(callback_in) {}
  GetContactFunctor callback;
};

struct RefreshArgs : public LookupArgs {
  RefreshArgs(const LookupArgs::OperationType &op_type,
              const NodeId &target,
              const uint16_t &num_contacts_requested,
              const OrderedContacts &close_contacts,
              PrivateKeyPtr private_key,
              const std::string &serialised_request,
              const std::string &serialised_request_signature)
      : LookupArgs(op_type, target, close_contacts, num_contacts_requested,
                   private_key),
        kSerialisedRequest(serialised_request),
        kSerialisedRequestSignature(serialised_request_signature) {
    BOOST_ASSERT(op_type == LookupArgs::kStoreRefresh ||
                 op_type == LookupArgs::kDeleteRefresh);
  }
  const std::string kSerialisedRequest, kSerialisedRequestSignature;
};

typedef std::shared_ptr<LookupArgs> LookupArgsPtr;
typedef std::shared_ptr<FindNodesArgs> FindNodesArgsPtr;
typedef std::shared_ptr<FindValueArgs> FindValueArgsPtr;
typedef std::shared_ptr<StoreArgs> StoreArgsPtr;
typedef std::shared_ptr<DeleteArgs> DeleteArgsPtr;
typedef std::shared_ptr<UpdateArgs> UpdateArgsPtr;
typedef std::shared_ptr<GetContactArgs> GetContactArgsPtr;
typedef std::shared_ptr<RefreshArgs> RefreshArgsPtr;

}  // namespace dht

}  // namespace maidsafe

#endif  // MAIDSAFE_DHT_NODE_IMPL_STRUCTS_H_

Added wiki_references/2017/software/MaidSafe_net/src_from_GitHub/the_repository_clones/MaidSafe-DHT/src/maidsafe/dht/return_codes.h version [8e9ebc2e6e].































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
/* Copyright (c) 2011 maidsafe.net limited
All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

    * Redistributions of source code must retain the above copyright notice,
    this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright notice,
    this list of conditions and the following disclaimer in the documentation
    and/or other materials provided with the distribution.
    * Neither the name of the maidsafe.net limited nor the names of its
    contributors may be used to endorse or promote products derived from this
    software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#ifndef MAIDSAFE_DHT_RETURN_CODES_H_
#define MAIDSAFE_DHT_RETURN_CODES_H_

#include "maidsafe/dht/version.h"

#if MAIDSAFE_DHT_VERSION != 3200
#  error This API is not compatible with the installed library.\
    Please update the maidsafe-dht library.
#endif


namespace maidsafe {
namespace dht {

enum ReturnCode {
  // General
  kSuccess = 0,
  kGeneralError = -300001,
  kUndefined = -300002,
  kPendingResult = -300003,
  kInvalidPointer = -300004,
  kTimedOut = -300005,

  // DataStore
  kEmptyKey = -301001,
  kZeroTTL = -301002,
  kFailedToModifyKeyValue = -301003,
  kMarkedForDeletion = -301004,

  // RoutingTable
  kOwnIdNotIncludable = -302001,
  kFailedToUpdateLastSeenTime = -302002,
  kNotInBrotherBucket = -302003,
  kOutwithClosest = -302004,
  kFailedToInsertNewContact = -302005,
  kFailedToFindContact = -302006,
  kFailedToSetPublicKey = -302007,
  kFailedToUpdateRankInfo = -302008,
  kFailedToSetPreferredEndpoint = -302009,
  kFailedToIncrementFailedRpcCount = -302010,

  // Node
  kNoOnlineBootstrapContacts = -303001,
  kInvalidBootstrapContacts = -303002,
  kNotListening = -303003,
  kNotJoined = -303004,
  kFindNodesFailed = -303005,
  kFoundTooFewNodes = -303006,
  kStoreTooFewNodes = -303007,
  kDeleteTooFewNodes = -303008,
  kUpdateTooFewNodes = -303009,
  kFailedToGetContact = -303010,
  kFailedToFindValue = 303011,  // value intentionally positive
  kFoundCachedCopyHolder = 303012,  // value intentionally positive
  kIterativeLookupFailed = -303013,
  kContactFailedToRespond = -303014,
  kValueAlreadyExists = -303015,
  kFailedValidation = -303016,

  // Contact
  kSerialisation = -304001,
  kParse = -304002
};

}  // namespace dht
}  // namespace maidsafe

#endif  // MAIDSAFE_DHT_RETURN_CODES_H_

Added wiki_references/2017/software/MaidSafe_net/src_from_GitHub/the_repository_clones/MaidSafe-DHT/src/maidsafe/dht/routing_table.cc version [90bd442e31].



































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
/* Copyright (c) 2009 maidsafe.net limited
All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

    * Redistributions of source code must retain the above copyright notice,
    this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright notice,
    this list of conditions and the following disclaimer in the documentation
    and/or other materials provided with the distribution.
    * Neither the name of the maidsafe.net limited nor the names of its
    contributors may be used to endorse or promote products derived from this
    software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include "maidsafe/dht/routing_table.h"

#include "maidsafe/common/utils.h"

#include "maidsafe/dht/return_codes.h"
#include "maidsafe/dht/utils.h"

namespace maidsafe {

namespace dht {

RoutingTable::RoutingTable(const NodeId &this_id, const uint16_t &k)
    : kThisId_(this_id),
      kDebugId_(DebugId(kThisId_)),
      k_(k),
      contacts_(),
      unvalidated_contacts_(),
      ping_oldest_contact_(new PingOldestContactPtr::element_type),
      validate_contact_(new ValidateContactPtr::element_type),
      ping_down_contact_(new PingDownContactPtr::element_type),
      shared_mutex_(),
      bucket_of_holder_(0) {}

RoutingTable::~RoutingTable() {
  UniqueLock unique_lock(shared_mutex_);
  unvalidated_contacts_.clear();
  contacts_.clear();
}

int RoutingTable::AddContact(const Contact &contact, RankInfoPtr rank_info) {
  const NodeId &node_id = contact.node_id();

  // If the contact has the same ID as the holder, return directly
  if (node_id == kThisId_) {
    DLOG(WARNING) << kDebugId_ << ": Can't add own ID to routing table.";
    return kOwnIdNotIncludable;
  }

  // Check if the contact is already in the routing table; if so, set its last
  // seen time to now (will bring it to the top)
  std::shared_ptr<UpgradeLock> upgrade_lock(new UpgradeLock(shared_mutex_));
  ContactsById key_indx = contacts_.get<NodeIdTag>();
  auto it_node = key_indx.find(node_id);
  if (it_node != key_indx.end()) {
    UpgradeToUniqueLock unique_lock(*upgrade_lock);
    // will update the num_failed_rpcs to 0 as well and update the IPs ports if
    // changed.
    if (contacts_.modify(it_node, ChangeLastSeen(contact))) {
      DLOG(WARNING) << kDebugId_ << ": Contact already in routing table "
                    << DebugId(contact);
      return kSuccess;
    } else {
      DLOG(WARNING) << kDebugId_ << ": Failed to update last seen time for "
                    << DebugId(contact);
      return kFailedToUpdateLastSeenTime;
    }
  } else {
    // put the contact into the unvalidated contacts container
    UnValidatedContactsById contact_indx =
        unvalidated_contacts_.get<NodeIdTag>();
    auto it_contact = contact_indx.find(node_id);
    if (it_contact == contact_indx.end()) {
      UnValidatedContact new_entry(contact, rank_info);
      unvalidated_contacts_.insert(new_entry);
      // fire the signal to validate the contact
      upgrade_lock->unlock();
      (*validate_contact_)(contact);
    }
    return kSuccess;
  }
}

void RoutingTable::InsertContact(const Contact &contact,
                                 RankInfoPtr rank_info,
                                 std::shared_ptr<UpgradeLock> upgrade_lock) {
  uint16_t common_leading_bits = KDistanceTo(contact.node_id());
  uint16_t target_kbucket_index = KBucketIndex(common_leading_bits);
  uint16_t k_bucket_size = KBucketSizeForKey(target_kbucket_index);

  // if the corresponding bucket is full
  if (k_bucket_size == k_) {
    // try to split the bucket if the new contact appears to be in the same
    // bucket as the holder
    if (target_kbucket_index == bucket_of_holder_) {
      SplitKbucket(upgrade_lock);
      InsertContact(contact, rank_info, upgrade_lock);
    } else {
      // try to apply ForceK, otherwise fire the signal
      int force_k_result(ForceKAcceptNewPeer(contact, target_kbucket_index,
                                             rank_info, upgrade_lock));
      if (force_k_result != kSuccess &&
          force_k_result != kFailedToInsertNewContact) {
        Contact oldest_contact = GetLastSeenContact(target_kbucket_index);
        // fire a signal here to notify
        (*ping_oldest_contact_)(oldest_contact, contact, rank_info);
      }
    }
  } else {
    // bucket not full, insert the contact into routing table
    RoutingTableContact new_routing_table_contact(contact, kThisId_,
                                                  rank_info,
                                                  common_leading_bits);
    new_routing_table_contact.kbucket_index = target_kbucket_index;
    UpgradeToUniqueLock unique_lock(*upgrade_lock);
    auto result = contacts_.insert(new_routing_table_contact);
    if (result.second) {
      DLOG(INFO) << kDebugId_ << ": Added node " << DebugId(contact) << ".  "
                 << contacts_.size() << " contacts.";
    } else {
      DLOG(WARNING) << kDebugId_ << ": Failed to insert node "
                    << DebugId(contact);
    }
  }
}

int RoutingTable::GetContact(const NodeId &node_id, Contact *contact) {
  if (!contact) {
    DLOG(WARNING) << kDebugId_ << ": Null pointer passed.";
    return kInvalidPointer;
  }
  SharedLock shared_lock(shared_mutex_);
  ContactsById key_indx = contacts_.get<NodeIdTag>();
  auto it = key_indx.find(node_id);
  if (it != key_indx.end()) {
    *contact = (*it).contact;
    return kSuccess;
  } else {
    *contact = Contact();
    return kFailedToFindContact;
  }
}

void RoutingTable::GetCloseContacts(
    const NodeId &target_id,
    const size_t &count,
    const std::vector<Contact> &exclude_contacts,
    std::vector<Contact> *close_contacts) {
  if (!close_contacts) {
    DLOG(WARNING) << kDebugId_ << ": Null pointer passed.";
    return;
  }
  SharedLock shared_lock(shared_mutex_);
  // the search will begin from a bucket having the similiar k-distance as the
  // target node to the current holder
  // then extend the range follows the rule:
  //      all kbuckets contains more common leading bits shall be considered
  //      if the total still smaller than the count, then recursively add
  //      kbuckets containing less leading bits till reach the count cap
  uint16_t start_kbucket_index = KBucketIndex(target_id);
  uint16_t end_kbucket_index = start_kbucket_index +1;

  uint32_t potential_size = KBucketSizeForKey(start_kbucket_index);
  uint32_t target_size = static_cast<uint32_t>(count + exclude_contacts.size());
  // extend the search range step 1: add all kbuckets containing more
  // common leading bits, the bucket contains the holder will always be the last
  while (end_kbucket_index <= bucket_of_holder_) {
    potential_size = potential_size + KBucketSizeForKey(end_kbucket_index);
    ++end_kbucket_index;
  }
  // extend the search range step 2:recursively add kbuckets containing
  // less common leading bits till reach the count cap
  while ((potential_size < target_size) && (start_kbucket_index > 0)) {
    --start_kbucket_index;
    potential_size = potential_size + KBucketSizeForKey(start_kbucket_index);
  }
  // once we have the search range, put all contacts in the range buckets into
  // a candidate container, using target_id to re-calculate the distance
  RoutingTableContactsContainer candidate_contacts;
  while (start_kbucket_index < end_kbucket_index) {
    bmi::index_iterator<RoutingTableContactsContainer,
        KBucketTag>::type ic0, ic1;
    boost::tuples::tie(ic0, ic1)
      = bmi::get<KBucketTag>(contacts_).equal_range(start_kbucket_index);
    while (ic0 != ic1) {
      // check if the candidate in the exclusion list
      auto it = std::find(exclude_contacts.begin(),
                          exclude_contacts.end(),
                          (*ic0).contact);
      // if not in the exclusion list, add the contact into the candidates
      // container
      if (it == exclude_contacts.end()) {
        RoutingTableContact new_contact((*ic0).contact, target_id, 0);
        candidate_contacts.insert(new_contact);
      }
      ++ic0;
    }
    ++start_kbucket_index;
  }
  // populate the result with the count defined top contacts
  // indexed by the new calculated distance
  ContactsByDistanceToThisId key_dist_indx
    = candidate_contacts.get<DistanceToThisIdTag>();
  uint32_t counter(0);
  auto it = key_dist_indx.begin();
  while ((counter < count) && (it != key_dist_indx.end())) {
    close_contacts->push_back((*it).contact);
    ++counter;
    ++it;
  }
  return;
}

void RoutingTable::Downlist(const NodeId &node_id) {
  SharedLock shared_lock(shared_mutex_);
  ContactsById key_indx = contacts_.get<NodeIdTag>();
  auto it = key_indx.find(node_id);
  if (it != key_indx.end())
    (*ping_down_contact_)((*it).contact);
}

int RoutingTable::SetPublicKey(const NodeId &node_id,
                               const std::string &new_public_key) {
  UpgradeLock upgrade_lock(shared_mutex_);
  ContactsById key_indx = contacts_.get<NodeIdTag>();
  auto it = key_indx.find(node_id);
  if (it == key_indx.end()) {
    DLOG(WARNING) << kDebugId_ << ": Failed to find node " << DebugId(node_id);
    return kFailedToFindContact;
  }
  UpgradeToUniqueLock unique_lock(upgrade_lock);
  if (key_indx.modify(it, ChangePublicKey(new_public_key))) {
    return kSuccess;
  } else {
    DLOG(WARNING) << kDebugId_ << ": Failed to set public key for node "
                  << DebugId(node_id);
    return kFailedToSetPublicKey;
  }
}

int RoutingTable::UpdateRankInfo(const NodeId &node_id,
                                 RankInfoPtr new_rank_info) {
  UpgradeLock upgrade_lock(shared_mutex_);
  ContactsById key_indx = contacts_.get<NodeIdTag>();
  auto it = key_indx.find(node_id);
  if (it == key_indx.end()) {
    DLOG(WARNING) << kDebugId_ << ": Failed to find node " << DebugId(node_id);
    return kFailedToFindContact;
  }
  UpgradeToUniqueLock unique_lock(upgrade_lock);
  if (key_indx.modify(it, ChangeRankInfo(new_rank_info))) {
    return kSuccess;
  } else {
    DLOG(WARNING) << kDebugId_ << ": Failed to update rank info for node "
                  << DebugId(node_id);
    return kFailedToUpdateRankInfo;
  }
}

int RoutingTable::SetPreferredEndpoint(const NodeId &node_id, const IP &ip) {
  UpgradeLock upgrade_lock(shared_mutex_);
  ContactsById key_indx = contacts_.get<NodeIdTag>();
  auto it = key_indx.find(node_id);
  if (it == key_indx.end()) {
    DLOG(WARNING) << kDebugId_ << ": Failed to find node " << DebugId(node_id);
    return kFailedToFindContact;
  }
  Contact new_local_contact((*it).contact);
  new_local_contact.SetPreferredEndpoint(ip);
  UpgradeToUniqueLock unique_lock(upgrade_lock);
  if (key_indx.modify(it, ChangeContact(new_local_contact))) {
    return kSuccess;
  } else {
    DLOG(WARNING) << kDebugId_ << ": Failed to set preferred endpt for node "
                  << DebugId(node_id);
    return kFailedToSetPreferredEndpoint;
  }
}

int RoutingTable::SetValidated(const NodeId &node_id, bool validated) {
  std::shared_ptr<UpgradeLock> upgrade_lock(new UpgradeLock(shared_mutex_));
  UnValidatedContactsById contact_indx =
      unvalidated_contacts_.get<NodeIdTag>();
  auto it_contact = contact_indx.find(node_id);

  // if the contact can be found in the un-validated contacts container
  if (it_contact != contact_indx.end()) {
    // If an un-validated entry proved to be valid remove it from un-validated
    // container and insert it into routing_table.  Otherwise, drop it.
    if (validated) {
      InsertContact((*it_contact).contact, (*it_contact).rank_info,
                    upgrade_lock);
    }
    UpgradeToUniqueLock unique_lock(*upgrade_lock);
    contact_indx.erase(it_contact);
    return kSuccess;
  }

  ContactsById key_indx = contacts_.get<NodeIdTag>();
  auto it = key_indx.find(node_id);
  if (it == key_indx.end()) {
    DLOG(WARNING) << kDebugId_ << ": Failed to find node " << DebugId(node_id);
    return kFailedToFindContact;
  }

  if (!validated) {
    // if the contact proved to be invalid, remove it from the routing_table.
    DLOG(WARNING) << kDebugId_ << ": Node " << DebugId(node_id)
                  << " removed from routing table - failed to validate.  "
                  << contacts_.size() << " contacts.";
    UpgradeToUniqueLock unique_lock(*upgrade_lock);
    key_indx.erase(it);
  }
  return kSuccess;
}

int RoutingTable::IncrementFailedRpcCount(const NodeId &node_id) {
  UpgradeLock upgrade_lock(shared_mutex_);
  ContactsById key_indx = contacts_.get<NodeIdTag>();
  auto it = key_indx.find(node_id);
  if (it == key_indx.end()) {
    DLOG(INFO) << kDebugId_ << ": Failed to find node " << DebugId(node_id);
    return kFailedToFindContact;
  }
  uint16_t num_failed_rpcs = (*it).num_failed_rpcs + 1;
  UpgradeToUniqueLock unique_lock(upgrade_lock);
  if (num_failed_rpcs > kFailedRpcTolerance) {
    key_indx.erase(it);
    DLOG(INFO) << kDebugId_ << ": Removed node " << DebugId(node_id) << ".  "
               << contacts_.size() << " contacts.";
    return kSuccess;
  } else {
    if (key_indx.modify(it, ChangeNumFailedRpc(num_failed_rpcs))) {
      DLOG(INFO) << kDebugId_ << ": Incremented failed rpc count for node "
                 << DebugId(node_id) << " to " << num_failed_rpcs;
      return kSuccess;
    } else {
      DLOG(WARNING) << kDebugId_ << ": Failed to increment failed rpc count "
                    << "for node " << DebugId(node_id);
      return kFailedToIncrementFailedRpcCount;
    }
  }
}

void RoutingTable::GetBootstrapContacts(std::vector<Contact> *contacts) {
  if (!contacts)
    return;

  SharedLock shared_lock(shared_mutex_);
  auto it = contacts_.get<BootstrapTag>().equal_range(true);
  contacts->clear();
  while (it.first != it.second)
    contacts->push_back((*it.first++).contact);

  if (contacts->size() < kMinBootstrapContacts) {
    it = contacts_.get<BootstrapTag>().equal_range(false);
    while (it.first != it.second)
      contacts->push_back((*it.first++).contact);
  }
}

RankInfoPtr RoutingTable::GetLocalRankInfo(const Contact &contact) {
  SharedLock shared_lock(shared_mutex_);
  ContactsById key_indx = contacts_.get<NodeIdTag>();
  auto it = key_indx.find(contact.node_id());
  if (it == key_indx.end()) {
    DLOG(WARNING) << kDebugId_ << ": Failed to find node " << DebugId(contact);
    return RankInfoPtr();
  } else {
    return (*it).rank_info;
  }
}

void RoutingTable::GetAllContacts(std::vector<Contact> *contacts) {
  if (!contacts) {
    DLOG(WARNING) << kDebugId_ << ": Null pointer passed.";
    return;
  }
  SharedLock shared_lock(shared_mutex_);
  ContactsById key_indx = contacts_.get<NodeIdTag>();
  auto it = key_indx.begin();
  auto it_end = key_indx.end();
  contacts->clear();
  contacts->reserve(distance(it, it_end));
  while (it != it_end) {
    contacts->push_back((*it).contact);
    ++it;
  }
}

PingOldestContactPtr RoutingTable::ping_oldest_contact() {
  return ping_oldest_contact_;
}

ValidateContactPtr RoutingTable::validate_contact() {
  return validate_contact_;
}

PingDownContactPtr RoutingTable::ping_down_contact() {
  return ping_down_contact_;
}

Contact RoutingTable::GetLastSeenContact(const uint16_t &kbucket_index) {
  auto pit = contacts_.get<KBucketLastSeenTag>().equal_range(boost::make_tuple(
      kbucket_index));
  return (*pit.first).contact;
}

uint16_t RoutingTable::KBucketIndex(const NodeId &key) {
//   if (key > NodeId::kMaxId)
//     return -1;
  uint16_t common_leading_bits = KDistanceTo(key);
  if (common_leading_bits > bucket_of_holder_)
    common_leading_bits = bucket_of_holder_;
  return common_leading_bits;
}

uint16_t RoutingTable::KBucketIndex(const uint16_t &common_leading_bits) {
  if (common_leading_bits > bucket_of_holder_)
    return bucket_of_holder_;
  return common_leading_bits;
}

uint16_t RoutingTable::KBucketCount() const {
  return bucket_of_holder_+1;
}

uint16_t RoutingTable::KBucketSizeForKey(const uint16_t &key) {
  if (key > bucket_of_holder_) {
    auto pit = contacts_.get<KBucketTag>().equal_range(bucket_of_holder_);
    return static_cast<uint16_t>(distance(pit.first, pit.second));
  } else {
    auto pit = contacts_.get<KBucketTag>().equal_range(key);
    return static_cast<uint16_t>(distance(pit.first, pit.second));
  }
}

void RoutingTable::SplitKbucket(std::shared_ptr<UpgradeLock> upgrade_lock) {
  // each time the split means:
  //    split the bucket of holder, contacts having common leading bits
  //    (bucket_of_holder_, 512) into (bucket_of_holder_+1,512) and
  //    bucket_of_holder_
  // modify all related contacts's kbucket index tag in the contact container
  auto pit = contacts_.get<KBucketTag>().equal_range(bucket_of_holder_);
  auto it_begin = pit.first;
  auto it_end = pit.second;
  std::vector<NodeId> contacts_need_change;
  while (it_begin != it_end) {
    if ((*it_begin).common_leading_bits > bucket_of_holder_) {
      // note, change the KBucket value here will cause re-sorting of the
      // multi-index container. So we can only collect the node_id of the
      // contacts need to be changed, then change their kbucket value later
      contacts_need_change.push_back((*it_begin).node_id);
    }
    ++it_begin;
  }
  ContactsById key_node_indx = contacts_.get<NodeIdTag>();
  UpgradeToUniqueLock unique_lock(*upgrade_lock);
  for (auto it = contacts_need_change.begin();
       it != contacts_need_change.end(); ++it) {
    auto it_contact = key_node_indx.find(*it);
    key_node_indx.modify(it_contact, ChangeKBucketIndex(bucket_of_holder_+1));
  }
  ++bucket_of_holder_;
}

int RoutingTable::ForceKAcceptNewPeer(
    const Contact &new_contact,
    const uint16_t &target_bucket,
    RankInfoPtr rank_info,
    std::shared_ptr<UpgradeLock> upgrade_lock) {
  uint16_t brother_bucket_of_holder = bucket_of_holder_ - 1;
  int kclosest_bucket_index = GetLeastCommonLeadingBitInKClosestContact();
  if ((brother_bucket_of_holder != target_bucket) &&
      (kclosest_bucket_index != target_bucket)) {
    return kNotInBrotherBucket;
  }
  // Calculate how many k closest neighbours belong to the brother bucket of
  // the peer
  int closest_outwith_bucket_of_holder =
      k_ - KBucketSizeForKey(bucket_of_holder_);
  if (closest_outwith_bucket_of_holder <= 0)
    return kOutwithClosest;

  // sort the brother bucket based on contacts' distance to the holder
  auto pit = contacts_.get<KBucketDistanceToThisIdTag>().equal_range(
      boost::make_tuple(target_bucket));
  // check if the new contact is among the k closest
  NodeId distance_to_target = kThisId_ ^ new_contact.node_id();
  // pit.second shall point to the furthest contact (need one step forward)
  // as the list will sorted from least to highest
  // while the least value of XOR distance means the nearest
  auto it_end = pit.second;
  --it_end;
  ContactsById key_node_indx = contacts_.get<NodeIdTag>();
  NodeId furthest_distance = (*it_end).distance_to_this_id;
  NodeId furthest_node = (*it_end).node_id;
  auto it_furthest = key_node_indx.find(furthest_node);

  if (furthest_distance <= distance_to_target)
    return kOutwithClosest;

  UpgradeToUniqueLock unique_lock(*upgrade_lock);
  contacts_.erase(it_furthest);
  RoutingTableContact new_local_contact(new_contact, kThisId_,
                                        rank_info,
                                        KDistanceTo(new_contact.node_id()));
  new_local_contact.kbucket_index = target_bucket;
  auto result = contacts_.insert(new_local_contact);
  if (result.second) {
    DLOG(INFO) << kDebugId_ << ": Added node " << DebugId(new_contact)
               << " via ForceK.  " << contacts_.size() << " contacts.";
    return kSuccess;
  } else {
    DLOG(WARNING) << kDebugId_ << ": Failed to insert node "
                  << DebugId(new_contact) << " via ForceK.";
    return kFailedToInsertNewContact;
  }
}

int RoutingTable::GetLeastCommonLeadingBitInKClosestContact() {
  std::vector<Contact> contacts, exclude_contacts;
  GetCloseContacts(kThisId_, k_, exclude_contacts, &contacts);
  ContactsById key_id_indx = contacts_.get<NodeIdTag>();
  auto it = key_id_indx.find(contacts[0].node_id());
  uint16_t kclosest_bucket_index = (*it).common_leading_bits;
  for (size_t i = 1; i < contacts.size(); ++i) {
    it = key_id_indx.find(contacts[i].node_id());
    if (kclosest_bucket_index > (*it).common_leading_bits)
      kclosest_bucket_index = (*it).common_leading_bits;
  }
  return kclosest_bucket_index;
}

uint16_t RoutingTable::KDistanceTo(const NodeId &rhs) const {
  uint16_t distance = 0;
  std::string this_id_binary = kThisId_.ToStringEncoded(NodeId::kBinary);
  std::string rhs_id_binary = rhs.ToStringEncoded(NodeId::kBinary);
  std::string::const_iterator this_it = this_id_binary.begin();
  std::string::const_iterator rhs_it = rhs_id_binary.begin();
  for (; ((this_it != this_id_binary.end()) && (*this_it == *rhs_it));
      ++this_it, ++rhs_it)
    ++distance;
  return distance;
}

size_t RoutingTable::Size() {
  SharedLock shared_lock(shared_mutex_);
  return contacts_.size();
}

void RoutingTable::Clear() {
  UniqueLock unique_lock(shared_mutex_);
  unvalidated_contacts_.clear();
  contacts_.clear();
  bucket_of_holder_ = 0;
}

}  // namespace dht

}  // namespace maidsafe

Added wiki_references/2017/software/MaidSafe_net/src_from_GitHub/the_repository_clones/MaidSafe-DHT/src/maidsafe/dht/routing_table.h version [116ae86efe].





































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
/* Copyright (c) 2009 maidsafe.net limited
All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

    * Redistributions of source code must retain the above copyright notice,
    this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright notice,
    this list of conditions and the following disclaimer in the documentation
    and/or other materials provided with the distribution.
    * Neither the name of the maidsafe.net limited nor the names of its
    contributors may be used to endorse or promote products derived from this
    software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#ifndef MAIDSAFE_DHT_ROUTING_TABLE_H_
#define MAIDSAFE_DHT_ROUTING_TABLE_H_

#include <cstdint>
#include <map>
#include <memory>
#include <string>
#include <vector>

#include "boost/date_time/posix_time/posix_time_types.hpp"
#include "boost/signals2/signal.hpp"
#include "boost/lambda/lambda.hpp"
#include "boost/lambda/bind.hpp"
#include "boost/lambda/if.hpp"
#ifdef __MSVC__
#  pragma warning(push)
#  pragma warning(disable: 4244)
#endif
#include "boost/multi_index_container.hpp"
#include "boost/multi_index/composite_key.hpp"
#include "boost/multi_index/ordered_index.hpp"
#include "boost/multi_index/identity.hpp"
#include "boost/multi_index/member.hpp"
#include "boost/multi_index/mem_fun.hpp"
#ifdef __MSVC__
#  pragma warning(pop)
#endif
#include "boost/thread/shared_mutex.hpp"
#include "boost/thread/locks.hpp"

#include "maidsafe/dht/contact.h"
#include "maidsafe/dht/node_id.h"
#include "maidsafe/dht/log.h"


namespace bptime = boost::posix_time;
namespace bmi = boost::multi_index;

namespace maidsafe {

namespace transport { struct Info; }

namespace dht {

namespace test {
class RoutingTableTest;
class RoutingTableSingleKTest;
class RoutingTableSingleKTest_FUNC_ForceKAcceptNewPeer_Test;
class ServicesTest;
class RoutingTableSingleKTest_BEH_MutexTestWithMultipleThread_Test;
}  // namespace test

class KBucket;

struct RoutingTableContact {
  RoutingTableContact(const Contact &contact,
                      const NodeId &holder_id,
                      const RankInfoPtr &rank_info,
                      uint16_t common_leading_bits)
      : contact(contact),
        node_id(contact.node_id()),
        public_key(),
        num_failed_rpcs(0),
        distance_to_this_id(holder_id ^ contact.node_id()),
        common_leading_bits(common_leading_bits),
        kbucket_index(0),
        last_seen(bptime::microsec_clock::universal_time()),
        rank_info(rank_info) {}
  RoutingTableContact(const Contact &contact,
                      const NodeId &holder_id,
                      uint16_t common_leading_bits)
      : contact(contact),
        node_id(contact.node_id()),
        public_key(),
        num_failed_rpcs(0),
        distance_to_this_id(holder_id ^ contact.node_id()),
        common_leading_bits(common_leading_bits),
        kbucket_index(0),
        last_seen(bptime::microsec_clock::universal_time()),
        rank_info() {}
  RoutingTableContact(const RoutingTableContact &other)
      : contact(other.contact),
        node_id(other.node_id),
        public_key(other.public_key),
        num_failed_rpcs(other.num_failed_rpcs),
        distance_to_this_id(other.distance_to_this_id),
        common_leading_bits(other.common_leading_bits),
        kbucket_index(other.kbucket_index),
        last_seen(other.last_seen),
        rank_info(other.rank_info) {}
  bool DirectConnected() const {
    return contact.IsDirectlyConnected();
  }
  bool operator<(const RoutingTableContact &other) const {
    return contact < other.contact;
  }
  Contact contact;
  NodeId node_id;
  std::string public_key;
  uint16_t num_failed_rpcs;
  NodeId distance_to_this_id;
  uint16_t common_leading_bits;
  // the index of the kbucket which is responsible for the contact
  uint16_t kbucket_index;
  bptime::ptime last_seen;
  RankInfoPtr rank_info;
};

struct ChangeContact {
  explicit ChangeContact(const Contact &contact) : contact(contact) {}
  // Anju: use nolint to satisfy multi-indexing
  void operator()(RoutingTableContact &routing_table_contact) {  // NOLINT
    routing_table_contact.contact = contact;
  }
  Contact contact;
};

struct ChangeKBucketIndex {
  explicit ChangeKBucketIndex(const uint16_t &new_kbucket_index)
      : new_kbucket_index(new_kbucket_index) {}
  // Anju: use nolint to satisfy multi-indexing
  void operator()(RoutingTableContact &routing_table_contact) {  // NOLINT
    routing_table_contact.kbucket_index = new_kbucket_index;
  }
  uint16_t new_kbucket_index;
};

struct ChangePublicKey {
  explicit ChangePublicKey(const std::string &new_public_key)
      : new_public_key(new_public_key) {}
  // Anju: use nolint to satisfy multi-indexing
  void operator()(RoutingTableContact &routing_table_contact) {  // NOLINT
    routing_table_contact.public_key = new_public_key;
  }
  std::string new_public_key;
};

struct ChangeRankInfo {
  explicit ChangeRankInfo(RankInfoPtr new_rank_info)
      : new_rank_info(new_rank_info) {}
  // Anju: use nolint to satisfy multi-indexing
  void operator()(RoutingTableContact &routing_table_contact) {  // NOLINT
    routing_table_contact.rank_info = new_rank_info;
  }
  RankInfoPtr new_rank_info;
};

struct ChangeNumFailedRpc {
  explicit ChangeNumFailedRpc(const uint16_t &new_num_failed_rpcs)
      : new_num_failed_rpcs(new_num_failed_rpcs) {}
  // Anju: use nolint to satisfy multi-indexing
  void operator()(RoutingTableContact &routing_table_contact) {  // NOLINT
    routing_table_contact.num_failed_rpcs = new_num_failed_rpcs;
  }
  uint16_t new_num_failed_rpcs;
};

struct ChangeLastSeen {
  explicit ChangeLastSeen(const Contact &contact_in) : contact(contact_in) {}
  // Anju: use nolint to satisfy multi-indexing
  void operator()(RoutingTableContact &routing_table_contact) {  // NOLINT
    if (!asymm::MatchingPublicKeys(routing_table_contact.contact.public_key(),
                                   contact.public_key())) {
      DLOG(WARNING) << "Contacts have different public keys.";
      return;
    }
    if (routing_table_contact.contact.public_key_id() !=
        contact.public_key_id()) {
      DLOG(WARNING) << "Contacts have different public key IDs.";
      return;
    }

    routing_table_contact.last_seen = bptime::microsec_clock::universal_time();
    routing_table_contact.num_failed_rpcs = 0;
    transport::Endpoint preferred =
       routing_table_contact.contact.PreferredEndpoint();
    routing_table_contact.contact = Contact(contact.node_id(),
                                            contact.endpoint(),
                                            contact.local_endpoints(),
                                            contact.rendezvous_endpoint(),
                                            contact.tcp443endpoint().ip != IP(),
                                            contact.tcp80endpoint().ip != IP(),
                                            contact.public_key_id(),
                                            contact.public_key(),
                                            contact.other_info());
    routing_table_contact.contact.SetPreferredEndpoint(preferred.ip);
  }
  Contact contact;
};

struct NodeIdTag;
struct DistanceToThisIdTag;
struct KBucketTag;
struct KBucketLastSeenTag;
struct KBucketDistanceToThisIdTag;
struct TimeLastSeenTag;
struct BootstrapTag;

// Struct to allow initialisation of RoutingTableContactsContainer to accept
// this node's ID as a parameter.
struct KadCloserToThisId {
  explicit KadCloserToThisId(const NodeId &id) : this_id(id) {}
  bool operator()(const RoutingTableContact &x,
                  const RoutingTableContact &y) const {
    return NodeId::CloserToTarget(x.node_id, y.node_id, this_id);
  }
  NodeId this_id;
};

typedef boost::multi_index_container<
  RoutingTableContact,
  bmi::indexed_by<
    bmi::ordered_unique<
      bmi::tag<NodeIdTag>,
      BOOST_MULTI_INDEX_MEMBER(RoutingTableContact, NodeId, node_id)
    >,
    bmi::ordered_non_unique<
      bmi::tag<DistanceToThisIdTag>,
      BOOST_MULTI_INDEX_MEMBER(RoutingTableContact, NodeId, distance_to_this_id)
    >,
    bmi::ordered_non_unique<
      bmi::tag<KBucketTag>,
      BOOST_MULTI_INDEX_MEMBER(RoutingTableContact, uint16_t, kbucket_index)
    >,
    bmi::ordered_non_unique<
      bmi::tag<KBucketLastSeenTag>,
      bmi::composite_key<
        RoutingTableContact,
        BOOST_MULTI_INDEX_MEMBER(RoutingTableContact, uint16_t, kbucket_index),
        BOOST_MULTI_INDEX_MEMBER(RoutingTableContact, bptime::ptime, last_seen)
      >
    >,
    bmi::ordered_non_unique<
      bmi::tag<KBucketDistanceToThisIdTag>,
      bmi::composite_key<
        RoutingTableContact,
        BOOST_MULTI_INDEX_MEMBER(RoutingTableContact, uint16_t, kbucket_index),
        BOOST_MULTI_INDEX_MEMBER(RoutingTableContact, NodeId,
                                 distance_to_this_id)
      >
    >,
    bmi::ordered_non_unique<
      bmi::tag<TimeLastSeenTag>,
      BOOST_MULTI_INDEX_MEMBER(RoutingTableContact, bptime::ptime, last_seen)
    >,
    bmi::ordered_non_unique<
      bmi::tag<BootstrapTag>,
      bmi::const_mem_fun<RoutingTableContact, bool,
                         &RoutingTableContact::DirectConnected>
    >
  >
> RoutingTableContactsContainer;

typedef RoutingTableContactsContainer::index<NodeIdTag>::type& ContactsById;
typedef RoutingTableContactsContainer::index<DistanceToThisIdTag>::type&
    ContactsByDistanceToThisId;

struct UnValidatedContact {
  UnValidatedContact(const Contact &contact, const RankInfoPtr &rank_info)
      : contact(contact), node_id(contact.node_id()), rank_info(rank_info) {}

  Contact contact;
  NodeId node_id;
  RankInfoPtr rank_info;
};

typedef boost::multi_index_container<
  UnValidatedContact,
  bmi::indexed_by<
    bmi::ordered_unique<
      bmi::tag<NodeIdTag>,
      boost::multi_index::member<UnValidatedContact, NodeId,
                                 &UnValidatedContact::node_id>
    >
  >
> UnValidatedContactsContainer;

typedef UnValidatedContactsContainer::index<NodeIdTag>::type&
        UnValidatedContactsById;


typedef std::shared_ptr<boost::signals2::signal<void(const Contact&,
                                                     const Contact&,
                                                     RankInfoPtr)>>
        PingOldestContactPtr;

typedef std::shared_ptr<boost::signals2::signal<void(const Contact&)>>
        ValidateContactPtr, PingDownContactPtr;

/** Object containing a node's Kademlia Routing Table and all its contacts.
 *  @class RoutingTable */
class RoutingTable {
 public:
  /** Constructor.  To create a routing table, in all cases the node ID and
   *  k closest contacts parameter must be provided.
   *  @param[in] this_id The routing table holder's Kademlia ID.
   *  @param[in] k Kademlia constant k. */
  RoutingTable(const NodeId &this_id, const uint16_t &k);
  /** Destructor. */
  ~RoutingTable();
  /** Add the given contact to the correct k-bucket; if it already
   *  exists, its status will be updated.  If the given k-bucket is full and not
   *  splittable, the signal ping_oldest_contact_ will be fired which will
   *  ultimately resolve whether the contact is added or not.
   *  @param[in] contact The new contact which needs to be added.
   *  @param[in] rank_info The contact's rank_info.
   *  @return Return code 0 for success, otherwise failure. */
  int AddContact(const Contact &contact, RankInfoPtr rank_info);
  /** Get the info of the contact based on the input Kademlia ID.
   *  @param[in] node_id The input Kademlia ID.
   *  @param[out] contact the return contact.
   *  @return Return code 0 for success, otherwise failure. */
  int GetContact(const NodeId &node_id, Contact *contact);
  /** Finds a number of known nodes closest to the target node in the current
   *  routing table.
   *  @param[in] target_id The Kademlia ID of the target node.
   *  @param[in] count Number of closest nodes looking for.
   *  @param[in] exclude_contacts List of contacts that shall be excluded.
   *  @param[out] close_contacts Result of the find closest contacts. */
  void GetCloseContacts(const NodeId &target_id,
                        const size_t &count,
                        const std::vector<Contact> &exclude_contacts,
                        std::vector<Contact> *close_contacts);
  /** Checks if node_id is in routing table, and if it is, fires
   *  ping_down_contact_ to see whether the contact is actually offline.*/
  void Downlist(const NodeId &node_id);
  /** Set one node's public key.
   *  @param[in] node_id The Kademlia ID of the target node.
   *  @param[in] new_public_key The new value of the public key.
   *  @return Return code 0 for success, otherwise failure. */
  int SetPublicKey(const NodeId &node_id, const std::string &new_public_key);
  /** Update one node's rank info.
   *  @param[in] node_id The Kademlia ID of the target node.
   *  @param[in] rank_info The new value of the rank info.
   *  @return Return code 0 for success, otherwise failure. */
  int UpdateRankInfo(const NodeId &node_id, RankInfoPtr rank_info);
  /** Set one node's preferred endpoint.
   *  @param[in] node_id The Kademlia ID of the target node.
   *  @param[in] ip The new preferred endpoint.
   *  @return Return code 0 for success, otherwise failure. */
  int SetPreferredEndpoint(const NodeId &node_id, const IP &ip);
  /** Set one node's validation status.
   *  @param[in] node_id The Kademlia ID of the target node.
   *  @param[in] validated The validation status.
   *  @return Return code 0 for success, otherwise failure. */
  int SetValidated(const NodeId &node_id, bool validated);
  /** Increase one node's failedRPC counter by one.  If the count exceeds the
   *  value of kFailedRpcTolerance, the contact is removed from the routing
   *  table.
   *  @param[in] node_id The Kademlia ID of the target node.
   *  @return Return code 0 for success, otherwise failure. */
  int IncrementFailedRpcCount(const NodeId &node_id);
  /** Get the routing table holder's direct-connected nodes.
   *  For a direct-connected node, there must be no rendezvous endpoint,
   *  but either of tcp443 or tcp80 may be true.
   *  @param[out] contacts The result of all directly connected contacts. */
  void GetBootstrapContacts(std::vector<Contact> *contacts);
  /** Get the local RankInfo of the contact
   *  @param[in] contact The contact to find
   *  @return The localRankInfo of the contact */
  RankInfoPtr GetLocalRankInfo(const Contact &contact);
  /** Get all contacts in the routing table
   *  @param[out] contacts All contacts in the routing table */
  void GetAllContacts(std::vector<Contact> *contacts);
  /** Getter.
   *  @return The ping_oldest_contact_ signal. */
  PingOldestContactPtr ping_oldest_contact();
  /** Getter.
   *  @return The validate_contact_ signal. */
  ValidateContactPtr validate_contact();
  /** Getter.
   *  @return The ping_down_contact_ signal. */
  PingDownContactPtr ping_down_contact();

  friend class test::RoutingTableTest;
  friend class test::RoutingTableSingleKTest;
  friend class test::RoutingTableSingleKTest_FUNC_ForceKAcceptNewPeer_Test;
  friend class test::ServicesTest;
  friend class
      test::RoutingTableSingleKTest_BEH_MutexTestWithMultipleThread_Test;

 private:
  typedef boost::shared_lock<boost::shared_mutex> SharedLock;
  typedef boost::upgrade_lock<boost::shared_mutex> UpgradeLock;
  typedef boost::unique_lock<boost::shared_mutex> UniqueLock;
  typedef boost::upgrade_to_unique_lock<boost::shared_mutex>
      UpgradeToUniqueLock;
  /** Return the contact which is the lastseen on in the target kbucket.
   *  @param[in] kbucket_index The index of the kbucket.
   *  @return The last seend contact in the kbucket. */
  Contact GetLastSeenContact(const uint16_t &kbucket_index);
  /** Calculate the index of the k-bucket which is responsible for
   *  the specified key (or ID).
   *  @param[in] key The Kademlia ID of the target node.
   *  @return The index of the k-bucket which is in responsible. */
  uint16_t KBucketIndex(const NodeId &key);
  /** Calculate the index of the k-bucket which is responsible for
   *  the specified common_leading_bits.
   *  @param[in] common_leading_bits The common_heading_bits the target node.
   *  @return The index of the k-bucket which is in responsible. */
  uint16_t KBucketIndex(const uint16_t &common_leading_bits);
  /** Getter.
   *  @return Num of kbuckets in the routing table. */
  uint16_t KBucketCount() const;
  /** Get the number of contacts in a specified kbucket
   *  @param[in] key The index of the target k-bucket.
   *  @return Num of contacts in the specified kbucket */
  uint16_t KBucketSizeForKey(const uint16_t &key);
  /** Insert a contact into the routing table.
   *  @param[in] contact The new contact which needs to be added
   *  @param[in] rank_info The contact's rank_info
   *  @param[in] upgrade_lock An UpgradeLock held on shared_mutex_ */
  void InsertContact(const Contact &contact,
                     RankInfoPtr rank_info,
                     std::shared_ptr<UpgradeLock> upgrade_lock);
  /** Bisect the k-bucket into two new ones.
   *  @param[in] upgrade_lock An UpgradeLock held on shared_mutex_ */
  void SplitKbucket(std::shared_ptr<UpgradeLock> upgrade_lock);
  /** Forces the brother k-bucket of the holder to accept a new contact which
   *  would normally be dropped if it is within the k closest contacts to the
   *  holder's ID.
   *  @param[in] new_contact The new contact needs to be added.
   *  @param[in] target_bucket The kbucket shall in responsible of the new
   *  contact
   *  @param[in] upgrade_lock An UpgradeLock held on shared_mutex_
   *  @return Return code 0 for success, otherwise failure. */
  int ForceKAcceptNewPeer(const Contact &new_contact,
                          const uint16_t &target_bucket,
                          RankInfoPtr rank_info,
                          std::shared_ptr<UpgradeLock> upgrade_lock);
  /** XOR KBucket distance between two kademlia IDs.
   *  Measured by the number of common leading bits.
   *  The less the value is, the further the distance (the wider range) is.
   *  @param[in] rhs NodeId to which this is XOR
   *  @return the number of common bits from the beginning */
  uint16_t KDistanceTo(const NodeId &rhs) const;
  int GetLeastCommonLeadingBitInKClosestContact();

  /** Getter.
   *  @return Num of contacts in the routing table. */
  size_t Size();
  /** Empty the routing table */
  void Clear();

  /** Holder's Kademlia ID */
  const NodeId kThisId_;
  /** Holder's Kademlia ID held as a human readable string for debugging */
  std::string kDebugId_;
  /** Kademlia k */
  const uint16_t k_;
  /** Multi_index container of all contacts */
  RoutingTableContactsContainer contacts_;
  /** Container of all un-validated contacts */
  UnValidatedContactsContainer unvalidated_contacts_;
  /** Signal to be fired when k-bucket is full and cannot be split.  In signal
   *  signature, last-seen contact is first, then new contact and new contact's
   *  rank info.  Slot should ping the old contact and if successful, should
   *  call AddContact for the old contact, or if unsuccessful, should call
   *  IncrementFailedRpcCount for the old contact.  If this removes the old
   *  contact, the slot should then call AddContact for the new contact. */
  PingOldestContactPtr ping_oldest_contact_;
  /** Signal to be fired when adding a new contact. The contact will be added
   *  into the routing table directly, but having the Validated tag to be false.
   *  The new added contact will be passed as signal signature. Slot should
   *  validate the contact, then set the corresponding Validated tag in the
   *  routing table or to remove the contact from the routing table, if
   *  validation failed. */
  ValidateContactPtr validate_contact_;
  /** Signal to be fired when we receive notification that a contact we hold is
   *  offline.  In signal signature, contact is first, then contact's rank info.
   *  Slot should ping the contact and if successful, should call AddContact for
   *  the contact, or if unsuccessful, should call IncrementFailedRpcCount for
   *  the down contact twice (once to represent the notifier's failed attempt to
   *  reach the node). */
  PingDownContactPtr ping_down_contact_;
  /** Thread safe mutex lock */
  boost::shared_mutex shared_mutex_;
  /** The index to the bucket that the holder shall sit in
   *  It shall always be the value that 1 greater than the brother bucket */
  uint16_t bucket_of_holder_;
};

}  // namespace dht

}  // namespace maidsafe

#endif  // MAIDSAFE_DHT_ROUTING_TABLE_H_

Added wiki_references/2017/software/MaidSafe_net/src_from_GitHub/the_repository_clones/MaidSafe-DHT/src/maidsafe/dht/rpcs.h version [35c18a6406].



















































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
/* Copyright (c) 2009 maidsafe.net limited
All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

    * Redistributions of source code must retain the above copyright notice,
    this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright notice,
    this list of conditions and the following disclaimer in the documentation
    and/or other materials provided with the distribution.
    * Neither the name of the maidsafe.net limited nor the names of its
    contributors may be used to endorse or promote products derived from this
    software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#ifndef MAIDSAFE_DHT_RPCS_H_
#define MAIDSAFE_DHT_RPCS_H_

#include <cstdint>
#include <string>
#include <utility>
#include <vector>

#include "boost/asio/io_service.hpp"
#include "boost/date_time/posix_time/posix_time_types.hpp"
#include "boost/tuple/tuple.hpp"

#include "maidsafe/common/utils.h"
#include "maidsafe/transport/transport.h"

#include "maidsafe/dht/node_id.h"
#include "maidsafe/dht/message_handler.h"
#ifdef __MSVC__
#  pragma warning(push)
#  pragma warning(disable: 4127 4244 4267)
#endif
#include "maidsafe/dht/rpcs.pb.h"
#ifdef __MSVC__
#  pragma warning(pop)
#endif
#include "maidsafe/dht/utils.h"
#include "maidsafe/dht/config.h"
#include "maidsafe/dht/contact.h"
#include "maidsafe/dht/rpcs_objects.h"
#include "maidsafe/dht/log.h"

namespace args = std::placeholders;


namespace maidsafe {

namespace dht {

typedef std::function<void(RankInfoPtr, const int&)> RpcPingFunctor,
                                                     RpcStoreFunctor,
                                                     RpcStoreRefreshFunctor,
                                                     RpcDeleteFunctor,
                                                     RpcDeleteRefreshFunctor;
typedef std::function<void(RankInfoPtr,
                           const int&,
                           const std::vector<ValueAndSignature>&,
                           const std::vector<Contact>&,
                           const Contact&)> RpcFindValueFunctor;
typedef std::function<void(RankInfoPtr,
                           const int&,
                           const std::vector<Contact>&)> RpcFindNodesFunctor;

struct RpcsFailurePeer {
 public:
  RpcsFailurePeer() : peer(), rpcs_failure(1) {}
  Contact peer;
  uint16_t rpcs_failure;
};

template <typename TransportType>
class Rpcs {
 public:
  Rpcs(boost::asio::io_service &asio_service, PrivateKeyPtr private_key)  // NOLINT (Fraser)
          : asio_service_(asio_service),
            kFailureTolerance_(2),
            contact_(),
            default_private_key_(private_key),
            connected_objects_() {}
  virtual ~Rpcs() {}
  virtual void Ping(PrivateKeyPtr private_key,
                    const Contact &peer,
                    RpcPingFunctor callback);
  virtual void FindValue(const Key &key,
                         const uint16_t &nodes_requested,
                         PrivateKeyPtr private_key,
                         const Contact &peer,
                         RpcFindValueFunctor callback);
  virtual void FindNodes(const Key &key,
                         const uint16_t &nodes_requested,
                         PrivateKeyPtr private_key,
                         const Contact &peer,
                         RpcFindNodesFunctor callback);
  virtual void Store(const Key &key,
                     const std::string &value,
                     const std::string &signature,
                     const boost::posix_time::seconds &ttl,
                     PrivateKeyPtr private_key,
                     const Contact &peer,
                     RpcStoreFunctor callback);
  virtual void StoreRefresh(
      const std::string &serialised_store_request,
      const std::string &serialised_store_request_signature,
      PrivateKeyPtr private_key,
      const Contact &peer,
      RpcStoreRefreshFunctor callback);
  virtual void Delete(const Key &key,
                      const std::string &value,
                      const std::string &signature,
                      PrivateKeyPtr private_key,
                      const Contact &peer,
                      RpcDeleteFunctor callback);
  virtual void DeleteRefresh(
      const std::string &serialised_delete_request,
      const std::string &serialised_delete_request_signature,
      PrivateKeyPtr private_key,
      const Contact &peer,
      RpcDeleteRefreshFunctor callback);
  virtual void Downlist(const std::vector<NodeId> &node_ids,
                        PrivateKeyPtr private_key,
                        const Contact &peer);
  void set_contact(const Contact &contact) { contact_ = contact; }

  virtual void Prepare(PrivateKeyPtr private_key,
                       TransportPtr &transport,
                       MessageHandlerPtr &message_handler);

  std::pair<std::string, std::string> MakeStoreRequestAndSignature(
    const Key &key,
    const std::string &value,
    const std::string &signature,
    const boost::posix_time::seconds &ttl,
    PrivateKeyPtr private_key);

  std::pair<std::string, std::string> MakeDeleteRequestAndSignature(
    const Key &key,
    const std::string &value,
    const std::string &signature,
    PrivateKeyPtr private_key);

 protected:
  boost::asio::io_service &asio_service_;
  const uint16_t kFailureTolerance_;

 private:
  Rpcs(const Rpcs&);
  Rpcs& operator=(const Rpcs&);
  void PingCallback(const std::string &random_data,
                    const transport::TransportCondition &transport_condition,
                    const transport::Info &info,
                    const protobuf::PingResponse &response,
                    const uint32_t &index,
                    RpcPingFunctor callback,
                    const std::string &message,
                    std::shared_ptr<RpcsFailurePeer> rpcs_failure_peer);

  void FindValueCallback(
      const transport::TransportCondition &transport_condition,
      const transport::Info &info,
      const protobuf::FindValueResponse &response,
      const uint32_t &index,
      RpcFindValueFunctor callback,
      const std::string &message,
      std::shared_ptr<RpcsFailurePeer> rpcs_failure_peer);

  void FindNodesCallback(
      const transport::TransportCondition &transport_condition,
      const transport::Info &info,
      const protobuf::FindNodesResponse &response,
      const uint32_t &index,
      RpcFindNodesFunctor callback,
      const std::string &message,
      std::shared_ptr<RpcsFailurePeer> rpcs_failure_peer);

  void StoreCallback(const transport::TransportCondition &transport_condition,
                     const transport::Info &info,
                     const protobuf::StoreResponse &response,
                     const uint32_t &index,
                     RpcStoreFunctor callback,
                     const std::string &message,
                     std::shared_ptr<RpcsFailurePeer> rpcs_failure_peer);

  void StoreRefreshCallback(
      const transport::TransportCondition &transport_condition,
      const transport::Info &info,
      const protobuf::StoreRefreshResponse &response,
      const uint32_t &index,
      RpcStoreRefreshFunctor callback,
      const std::string &message,
      std::shared_ptr<RpcsFailurePeer> rpcs_failure_peer);

  void DeleteCallback(const transport::TransportCondition &transport_condition,
                      const transport::Info &info,
                      const protobuf::DeleteResponse &response,
                      const uint32_t &index,
                      RpcDeleteFunctor callback,
                      const std::string &message,
                      std::shared_ptr<RpcsFailurePeer> rpcs_failure_peer);

  void DeleteRefreshCallback(
      const transport::TransportCondition &transport_condition,
      const transport::Info &info,
      const protobuf::DeleteRefreshResponse &response,
      const uint32_t &index,
      RpcDeleteRefreshFunctor callback,
      const std::string &message,
      std::shared_ptr<RpcsFailurePeer> rpcs_failure_peer);

  Contact contact_;
  PrivateKeyPtr default_private_key_;
  ConnectedObjectsList connected_objects_;
};



template <typename TransportType>
void Rpcs<TransportType>::Ping(PrivateKeyPtr private_key,
                               const Contact &peer,
                               RpcPingFunctor callback) {
  TransportPtr transport;
  MessageHandlerPtr message_handler;
  Prepare(private_key, transport, message_handler);
  uint32_t object_indx =
      connected_objects_.AddObject(transport, message_handler);

  protobuf::PingRequest request;
  *request.mutable_sender() = ToProtobuf(contact_);
  std::string random_data(RandomString(50 + (RandomUint32() % 50)));
  request.set_ping(random_data);
  std::shared_ptr<RpcsFailurePeer> rpcs_failure_peer(new RpcsFailurePeer);
  rpcs_failure_peer->peer = peer;
  std::string message(message_handler->WrapMessage(request, peer.public_key()));

  // Connect callback to message handler for incoming parsed response or error
  message_handler->on_ping_response()->connect(
      std::bind(&Rpcs::PingCallback, this, random_data, transport::kSuccess,
                args::_1, args::_2, object_indx, callback, message,
                rpcs_failure_peer));
  message_handler->on_error()->connect(
      std::bind(&Rpcs::PingCallback, this, random_data, args::_1,
                transport::Info(), protobuf::PingResponse(), object_indx,
                callback, message, rpcs_failure_peer));
  DLOG(INFO) << "\t2 " << DebugId(contact_) << " PING to " << DebugId(peer);
  transport->Send(message,
                  peer.PreferredEndpoint(),
                  transport::kDefaultInitialTimeout);
}

template <typename TransportType>
void Rpcs<TransportType>::FindValue(const Key &key,
                                    const uint16_t &nodes_requested,
                                    PrivateKeyPtr private_key,
                                    const Contact &peer,
                                    RpcFindValueFunctor callback) {
  TransportPtr transport;
  MessageHandlerPtr message_handler;
  Prepare(private_key, transport, message_handler);
  uint32_t object_indx =
      connected_objects_.AddObject(transport, message_handler);

  protobuf::FindValueRequest request;
  *request.mutable_sender() = ToProtobuf(contact_);
  request.set_key(key.String());
  request.set_num_nodes_requested(nodes_requested);
  std::shared_ptr<RpcsFailurePeer> rpcs_failure_peer(new RpcsFailurePeer);
  rpcs_failure_peer->peer = peer;

  std::string message =
      message_handler->WrapMessage(request, peer.public_key());
  // Connect callback to message handler for incoming parsed response or error
  message_handler->on_find_value_response()->connect(std::bind(
      &Rpcs::FindValueCallback, this, transport::kSuccess, args::_1, args::_2,
      object_indx, callback, message, rpcs_failure_peer));
  message_handler->on_error()->connect(std::bind(
      &Rpcs::FindValueCallback, this, args::_1, transport::Info(),
      protobuf::FindValueResponse(), object_indx, callback, message,
      rpcs_failure_peer));
  DLOG(INFO) << "\t" << DebugId(contact_) << " FIND_VALUE to " << DebugId(peer);
  transport->Send(message, peer.PreferredEndpoint(),
                  transport::kDefaultInitialTimeout);
}

template <typename TransportType>
void Rpcs<TransportType>::FindNodes(const Key &key,
                                    const uint16_t &nodes_requested,
                                    PrivateKeyPtr private_key,
                                    const Contact &peer,
                                    RpcFindNodesFunctor callback) {
  TransportPtr transport;
  MessageHandlerPtr message_handler;
  Prepare(private_key, transport, message_handler);
  uint32_t object_indx =
      connected_objects_.AddObject(transport, message_handler);

  protobuf::FindNodesRequest request;
  *request.mutable_sender() = ToProtobuf(contact_);
  request.set_key(key.String());
  request.set_num_nodes_requested(nodes_requested);
  std::shared_ptr<RpcsFailurePeer> rpcs_failure_peer(new RpcsFailurePeer);
  rpcs_failure_peer->peer = peer;

  std::string message =
      message_handler->WrapMessage(request, peer.public_key());
  // Connect callback to message handler for incoming parsed response or error
  message_handler->on_find_nodes_response()->connect(std::bind(
      &Rpcs::FindNodesCallback, this, transport::kSuccess, args::_1, args::_2,
      object_indx, callback, message, rpcs_failure_peer));
  message_handler->on_error()->connect(std::bind(
      &Rpcs::FindNodesCallback, this, args::_1, transport::Info(),
      protobuf::FindNodesResponse(), object_indx, callback, message,
      rpcs_failure_peer));
  DLOG(INFO) << "\t" << DebugId(contact_) << " FIND_NODES to " << DebugId(peer);
  transport->Send(message, peer.PreferredEndpoint(),
                  transport::kDefaultInitialTimeout);
}

template <typename TransportType>
void Rpcs<TransportType>::Store(const Key &key,
                                const std::string &value,
                                const std::string &signature,
                                const boost::posix_time::seconds &ttl,
                                PrivateKeyPtr private_key,
                                const Contact &peer,
                                RpcStoreFunctor callback) {
  TransportPtr transport;
  MessageHandlerPtr message_handler;
  Prepare(private_key, transport, message_handler);
  uint32_t object_indx =
      connected_objects_.AddObject(transport, message_handler);

  protobuf::StoreRequest request;
  *request.mutable_sender() = ToProtobuf(contact_);
  request.set_key(key.String());
  std::shared_ptr<RpcsFailurePeer> rpcs_failure_peer(new RpcsFailurePeer);
  rpcs_failure_peer->peer = peer;

  protobuf::SignedValue *signed_value(request.mutable_signed_value());
  signed_value->set_value(value);
  signed_value->set_signature(signature);
  request.set_ttl(ttl.is_pos_infinity() ? -1 : ttl.total_seconds());
  std::string message =
      message_handler->WrapMessage(request, peer.public_key());
  // Connect callback to message handler for incoming parsed response or error
  message_handler->on_store_response()->connect(std::bind(
      &Rpcs::StoreCallback, this, transport::kSuccess, args::_1, args::_2,
      object_indx, callback, message, rpcs_failure_peer));
  message_handler->on_error()->connect(std::bind(
      &Rpcs::StoreCallback, this, args::_1, transport::Info(),
      protobuf::StoreResponse(), object_indx, callback, message,
      rpcs_failure_peer));
  DLOG(INFO) << "\t" << DebugId(contact_) << " STORE to " << DebugId(peer);
  transport->Send(message, peer.PreferredEndpoint(),
                  transport::kDefaultInitialTimeout);
}

template <typename TransportType>
void Rpcs<TransportType>::StoreRefresh(
    const std::string &serialised_store_request,
    const std::string &serialised_store_request_signature,
    PrivateKeyPtr private_key,
    const Contact &peer,
    RpcStoreRefreshFunctor callback) {
  TransportPtr transport;
  MessageHandlerPtr message_handler;
  Prepare(private_key, transport, message_handler);
  uint32_t object_indx =
      connected_objects_.AddObject(transport, message_handler);

  protobuf::StoreRefreshRequest request;
  std::shared_ptr<RpcsFailurePeer> rpcs_failure_peer(new RpcsFailurePeer);
  rpcs_failure_peer->peer = peer;

  *request.mutable_sender() = ToProtobuf(contact_);
  request.set_serialised_store_request(serialised_store_request);
  request.set_serialised_store_request_signature(
      serialised_store_request_signature);
  std::string message =
      message_handler->WrapMessage(request, peer.public_key());
  // Connect callback to message handler for incoming parsed response or error
  message_handler->on_store_refresh_response()->connect(std::bind(
      &Rpcs::StoreRefreshCallback, this, transport::kSuccess, args::_1,
      args::_2, object_indx, callback, message, rpcs_failure_peer));
  message_handler->on_error()->connect(std::bind(
      &Rpcs::StoreRefreshCallback, this, args::_1, transport::Info(),
      protobuf::StoreRefreshResponse(), object_indx, callback, message,
      rpcs_failure_peer));
  DLOG(INFO) << "\t" << DebugId(contact_) << " STORE_REFRESH to "
             << DebugId(peer);
  transport->Send(message, peer.PreferredEndpoint(),
                  transport::kDefaultInitialTimeout);
}

template <typename TransportType>
void Rpcs<TransportType>::Delete(const Key &key,
                                 const std::string &value,
                                 const std::string &signature,
                                 PrivateKeyPtr private_key,
                                 const Contact &peer,
                                 RpcDeleteFunctor callback) {
  TransportPtr transport;
  MessageHandlerPtr message_handler;
  Prepare(private_key, transport, message_handler);
  uint32_t object_indx =
      connected_objects_.AddObject(transport, message_handler);

  protobuf::DeleteRequest request;
  std::shared_ptr<RpcsFailurePeer> rpcs_failure_peer(new RpcsFailurePeer);
  rpcs_failure_peer->peer = peer;

  *request.mutable_sender() = ToProtobuf(contact_);
  request.set_key(key.String());
  protobuf::SignedValue *signed_value(request.mutable_signed_value());
  signed_value->set_value(value);
  signed_value->set_signature(signature);
  std::string message =
      message_handler->WrapMessage(request, peer.public_key());
  // Connect callback to message handler for incoming parsed response or error
  message_handler->on_delete_response()->connect(std::bind(
      &Rpcs::DeleteCallback, this, transport::kSuccess, args::_1, args::_2,
      object_indx, callback, message, rpcs_failure_peer));
  message_handler->on_error()->connect(std::bind(
      &Rpcs::DeleteCallback, this, args::_1, transport::Info(),
      protobuf::DeleteResponse(), object_indx, callback, message,
      rpcs_failure_peer));
  DLOG(INFO) << "\t" << DebugId(contact_) << " DELETE to " << DebugId(peer);
  transport->Send(message, peer.PreferredEndpoint(),
                  transport::kDefaultInitialTimeout);
}

template <typename TransportType>
void Rpcs<TransportType>::DeleteRefresh(
    const std::string &serialised_delete_request,
    const std::string &serialised_delete_request_signature,
    PrivateKeyPtr private_key,
    const Contact &peer,
    RpcDeleteRefreshFunctor callback) {
  TransportPtr transport;
  MessageHandlerPtr message_handler;
  Prepare(private_key, transport, message_handler);
  uint32_t object_indx =
      connected_objects_.AddObject(transport, message_handler);

  protobuf::DeleteRefreshRequest request;
  std::shared_ptr<RpcsFailurePeer> rpcs_failure_peer(new RpcsFailurePeer);
  rpcs_failure_peer->peer = peer;

  *request.mutable_sender() = ToProtobuf(contact_);
  request.set_serialised_delete_request(serialised_delete_request);
  request.set_serialised_delete_request_signature(
      serialised_delete_request_signature);
  std::string message =
      message_handler->WrapMessage(request, peer.public_key());
  // Connect callback to message handler for incoming parsed response or error
  message_handler->on_delete_refresh_response()->connect(std::bind(
      &Rpcs::DeleteRefreshCallback, this, transport::kSuccess, args::_1,
      args::_2, object_indx, callback, message, rpcs_failure_peer));
  message_handler->on_error()->connect(std::bind(
      &Rpcs::DeleteRefreshCallback, this, args::_1, transport::Info(),
      protobuf::DeleteRefreshResponse(), object_indx, callback, message,
      rpcs_failure_peer));
  DLOG(INFO) << "\t" << DebugId(contact_) << " DELETE_REFRESH to "
             << DebugId(peer);
  transport->Send(message, peer.PreferredEndpoint(),
                  transport::kDefaultInitialTimeout);
}

template <typename TransportType>
void Rpcs<TransportType>::Downlist(const std::vector<NodeId> &node_ids,
                                   PrivateKeyPtr private_key,
                                   const Contact &peer) {
  TransportPtr transport;
  MessageHandlerPtr message_handler;
  Prepare(private_key, transport, message_handler);
  connected_objects_.AddObject(transport, message_handler);
  protobuf::DownlistNotification notification;
  *notification.mutable_sender() = ToProtobuf(contact_);
  for (size_t i = 0; i < node_ids.size(); ++i)
    notification.add_node_ids(node_ids[i].String());
  std::string message = message_handler->WrapMessage(notification,
                                                     peer.public_key());
  std::string downlist_ids;
  for (size_t i = 0; i < node_ids.size(); ++i)
    downlist_ids += " [" + DebugId(node_ids[i]) + "]";

  DLOG(INFO) << "\t" << DebugId(contact_) << " DOWNLIST " << downlist_ids
            << " to " << DebugId(peer);
  transport->Send(message,
                  peer.PreferredEndpoint(),
                  transport::kDefaultInitialTimeout);
}

template <typename TransportType>
void Rpcs<TransportType>::PingCallback(
    const std::string &random_data,
    const transport::TransportCondition &transport_condition,
    const transport::Info &info,
    const protobuf::PingResponse &response,
    const uint32_t &index,
    RpcPingFunctor callback,
    const std::string &message,
    std::shared_ptr<RpcsFailurePeer> rpcs_failure_peer) {
  DLOG(INFO) << "\t" << DebugId(contact_) << " PING response from "
             << DebugId(rpcs_failure_peer->peer);
  if ((transport_condition != transport::kSuccess) &&
      (rpcs_failure_peer->rpcs_failure < kFailureTolerance_)) {
    ++(rpcs_failure_peer->rpcs_failure);
    TransportPtr transport = connected_objects_.GetTransport(index);
    transport->Send(message,
                    rpcs_failure_peer->peer.PreferredEndpoint(),
                    transport::kDefaultInitialTimeout);
  } else {
    connected_objects_.RemoveObject(index);
    if (transport_condition != transport::kSuccess) {
      callback(RankInfoPtr(new transport::Info(info)), transport_condition);
      return;
    }
    if (response.IsInitialized() && response.echo() == random_data) {
      callback(RankInfoPtr(new transport::Info(info)), transport::kSuccess);
    } else {
      callback(RankInfoPtr(new transport::Info(info)), transport::kError);
    }
  }
}

template <typename TransportType>
void Rpcs<TransportType>::FindValueCallback(
    const transport::TransportCondition &transport_condition,
    const transport::Info &info,
    const protobuf::FindValueResponse &response,
    const uint32_t &index,
    RpcFindValueFunctor callback,
    const std::string &message,
    std::shared_ptr<RpcsFailurePeer> rpcs_failure_peer) {
  if ((transport_condition != transport::kSuccess) &&
    (rpcs_failure_peer->rpcs_failure < kFailureTolerance_)) {
    ++(rpcs_failure_peer->rpcs_failure);
    TransportPtr transport = connected_objects_.GetTransport(index);
    transport->Send(
        message, rpcs_failure_peer->peer.PreferredEndpoint(),
        transport::kDefaultInitialTimeout);
  } else {
    connected_objects_.RemoveObject(index);

    std::vector<ValueAndSignature> values_and_signatures;
    std::vector<Contact> contacts;
    Contact cached_copy_holder;

    if (transport_condition != transport::kSuccess) {
      callback(RankInfoPtr(new transport::Info(info)), transport_condition,
               values_and_signatures, contacts, cached_copy_holder);
      return;
    }
    if (!response.IsInitialized() || !response.result()) {
      callback(RankInfoPtr(new transport::Info(info)), transport::kError,
               values_and_signatures, contacts, cached_copy_holder);
      return;
    }

    if (response.has_cached_copy_holder()) {
      cached_copy_holder = FromProtobuf(response.cached_copy_holder());
      callback(RankInfoPtr(new transport::Info(info)),
               kFoundCachedCopyHolder, values_and_signatures, contacts,
               cached_copy_holder);
      return;
    }

    if (response.signed_values_size() != 0) {
      for (int i = 0; i < response.signed_values_size(); ++i) {
        values_and_signatures.push_back(
            std::make_pair(response.signed_values(i).value(),
                           response.signed_values(i).signature()));
      }
      DLOG(INFO) << "\t" << DebugId(contact_) << " FIND_VALUE response from "
                 << DebugId(rpcs_failure_peer->peer) << " found "
                 << values_and_signatures.size() << " values.";
      callback(RankInfoPtr(new transport::Info(info)), kSuccess,
               values_and_signatures, contacts, cached_copy_holder);
      return;
    }

    if (response.closest_nodes_size() != 0) {
      for (int i = 0; i < response.closest_nodes_size(); ++i)
        contacts.push_back(FromProtobuf(response.closest_nodes(i)));
      DLOG(INFO) << "\t" << DebugId(contact_) << " FIND_VALUE response from "
                 << DebugId(rpcs_failure_peer->peer) << " found "
                 << contacts.size() << " contacts.";
      callback(RankInfoPtr(new transport::Info(info)), kFailedToFindValue,
               values_and_signatures, contacts, cached_copy_holder);
      return;
    }
    callback(RankInfoPtr(new transport::Info(info)), kIterativeLookupFailed,
             values_and_signatures, contacts, cached_copy_holder);
  }
}

template <typename TransportType>
void Rpcs<TransportType>::FindNodesCallback(
    const transport::TransportCondition &transport_condition,
    const transport::Info &info,
    const protobuf::FindNodesResponse &response,
    const uint32_t &index,
    RpcFindNodesFunctor callback,
    const std::string &message,
    std::shared_ptr<RpcsFailurePeer> rpcs_failure_peer) {
  if ((transport_condition != transport::kSuccess) &&
      (rpcs_failure_peer->rpcs_failure < kFailureTolerance_)) {
    ++(rpcs_failure_peer->rpcs_failure);
    TransportPtr transport = connected_objects_.GetTransport(index);
    transport->Send(
        message, rpcs_failure_peer->peer.PreferredEndpoint(),
        transport::kDefaultInitialTimeout);
  } else {
    connected_objects_.RemoveObject(index);
    std::vector<Contact> contacts;
    if (transport_condition != transport::kSuccess) {
      callback(RankInfoPtr(new transport::Info(info)), transport_condition,
               contacts);
      return;
    }
    if (!response.IsInitialized() || !response.result()) {
      callback(RankInfoPtr(new transport::Info(info)), transport::kError,
               contacts);
      return;
    }

    if (response.closest_nodes_size() != 0) {
      for (int i = 0; i < response.closest_nodes_size(); ++i)
        contacts.push_back(FromProtobuf(response.closest_nodes(i)));
      callback(RankInfoPtr(new transport::Info(info)), transport::kSuccess,
               contacts);
      return;
    }
    callback(RankInfoPtr(new transport::Info(info)), kIterativeLookupFailed,
             contacts);
  }
}

template <typename TransportType>
void Rpcs<TransportType>::StoreCallback(
    const transport::TransportCondition &transport_condition,
    const transport::Info &info,
    const protobuf::StoreResponse &response,
    const uint32_t &index,
    RpcStoreFunctor callback,
    const std::string &message,
    std::shared_ptr<RpcsFailurePeer> rpcs_failure_peer) {
  if ((transport_condition != transport::kSuccess) &&
      (rpcs_failure_peer->rpcs_failure < kFailureTolerance_)) {
    ++(rpcs_failure_peer->rpcs_failure);
    TransportPtr transport = connected_objects_.GetTransport(index);
    transport->Send(
        message, rpcs_failure_peer->peer.PreferredEndpoint(),
        transport::kDefaultInitialTimeout);
  } else {
    connected_objects_.RemoveObject(index);
    if (transport_condition != transport::kSuccess) {
      callback(RankInfoPtr(new transport::Info(info)), transport_condition);
      return;
    }
    if (response.IsInitialized() && response.result())
      callback(RankInfoPtr(new transport::Info(info)), transport::kSuccess);
    else
      callback(RankInfoPtr(new transport::Info(info)), transport::kError);
  }
}

template <typename TransportType>
void Rpcs<TransportType>::StoreRefreshCallback(
    const transport::TransportCondition &transport_condition,
    const transport::Info &info,
    const protobuf::StoreRefreshResponse &response,
    const uint32_t &index,
    RpcStoreRefreshFunctor callback,
    const std::string &message,
    std::shared_ptr<RpcsFailurePeer> rpcs_failure_peer) {
  if ((transport_condition != transport::kSuccess) &&
      (rpcs_failure_peer->rpcs_failure < kFailureTolerance_)) {
    ++(rpcs_failure_peer->rpcs_failure);
    TransportPtr transport = connected_objects_.GetTransport(index);
    transport->Send(
        message, rpcs_failure_peer->peer.PreferredEndpoint(),
        transport::kDefaultInitialTimeout);
  } else {
    connected_objects_.RemoveObject(index);
    if (transport_condition != transport::kSuccess) {
      callback(RankInfoPtr(new transport::Info(info)), transport_condition);
      return;
    }
    if (response.IsInitialized() && response.result())
      callback(RankInfoPtr(new transport::Info(info)), transport::kSuccess);
    else
      callback(RankInfoPtr(new transport::Info(info)), transport::kError);
  }
}

template <typename TransportType>
void Rpcs<TransportType>::DeleteCallback(
    const transport::TransportCondition &transport_condition,
    const transport::Info &info,
    const protobuf::DeleteResponse &response,
    const uint32_t &index,
    RpcDeleteFunctor callback,
    const std::string &message,
    std::shared_ptr<RpcsFailurePeer> rpcs_failure_peer) {
  if ((transport_condition != transport::kSuccess) &&
      (rpcs_failure_peer->rpcs_failure < kFailureTolerance_)) {
    ++(rpcs_failure_peer->rpcs_failure);
    TransportPtr transport = connected_objects_.GetTransport(index);
    transport->Send(
        message, rpcs_failure_peer->peer.PreferredEndpoint(),
        transport::kDefaultInitialTimeout);
  } else {
    connected_objects_.RemoveObject(index);
    if (transport_condition != transport::kSuccess) {
      callback(RankInfoPtr(new transport::Info(info)), transport_condition);
      return;
    }
    if (response.IsInitialized() && response.result())
      callback(RankInfoPtr(new transport::Info(info)), transport::kSuccess);
    else
      callback(RankInfoPtr(new transport::Info(info)), transport::kError);
  }
}

template <typename TransportType>
void Rpcs<TransportType>::DeleteRefreshCallback(
    const transport::TransportCondition &transport_condition,
    const transport::Info &info,
    const protobuf::DeleteRefreshResponse &response,
    const uint32_t &index,
    RpcDeleteRefreshFunctor callback,
    const std::string &message,
    std::shared_ptr<RpcsFailurePeer> rpcs_failure_peer) {
  if ((transport_condition != transport::kSuccess) &&
      (rpcs_failure_peer->rpcs_failure < kFailureTolerance_)) {
    ++(rpcs_failure_peer->rpcs_failure);
    TransportPtr transport = connected_objects_.GetTransport(index);
    transport->Send(
        message, rpcs_failure_peer->peer.PreferredEndpoint(),
        transport::kDefaultInitialTimeout);
  } else {
    connected_objects_.RemoveObject(index);
    if (transport_condition != transport::kSuccess) {
      callback(RankInfoPtr(new transport::Info(info)), transport_condition);
      return;
    }
    if (response.IsInitialized() && response.result())
      callback(RankInfoPtr(new transport::Info(info)), transport::kSuccess);
    else
      callback(RankInfoPtr(new transport::Info(info)), transport::kError);
  }
}

template <typename TransportType>
void Rpcs<TransportType>::Prepare(PrivateKeyPtr private_key,
                                  TransportPtr &transport,
                                  MessageHandlerPtr &message_handler) {
  transport.reset(new TransportType(asio_service_));
  message_handler.reset(new MessageHandler(private_key ? private_key :
                                                        default_private_key_));
  // Connect message handler to transport for incoming raw messages
  transport->on_message_received()->connect(
      transport::OnMessageReceived::element_type::slot_type(
          &MessageHandler::OnMessageReceived, message_handler.get(),
          _1, _2, _3, _4).track_foreign(message_handler));
  transport->on_error()->connect(
      transport::OnError::element_type::slot_type(
          &MessageHandler::OnError, message_handler.get(),
          _1, _2).track_foreign(message_handler));
}

template <typename T>
std::pair<std::string, std::string> Rpcs<T>::MakeStoreRequestAndSignature(
    const Key &key,
    const std::string &value,
    const std::string &signature,
    const boost::posix_time::seconds &ttl,
    PrivateKeyPtr private_key) {
  MessageHandlerPtr message_handler(new MessageHandler(private_key));

  protobuf::StoreRequest request;
  *request.mutable_sender() = ToProtobuf(contact_);
  request.set_key(key.String());

  protobuf::SignedValue *signed_value(request.mutable_signed_value());
  signed_value->set_value(value);
  signed_value->set_signature(signature);
  request.set_ttl(ttl.is_pos_infinity() ? -1 : ttl.total_seconds());
  std::string message(request.SerializeAsString());
  std::string message_signature;
  asymm::Sign(boost::lexical_cast<std::string>(kStoreRequest) + message,
             *private_key,
             &message_signature);
  return std::make_pair(message, message_signature);
}

template <typename T>
std::pair<std::string, std::string> Rpcs<T>::MakeDeleteRequestAndSignature(
    const Key &key,
    const std::string &value,
    const std::string &signature,
    PrivateKeyPtr private_key) {
  MessageHandlerPtr message_handler(new MessageHandler(private_key));

  protobuf::DeleteRequest request;
  *request.mutable_sender() = ToProtobuf(contact_);
  request.set_key(key.String());

  protobuf::SignedValue *signed_value(request.mutable_signed_value());
  signed_value->set_value(value);
  signed_value->set_signature(signature);

  std::string message(request.SerializeAsString());
  std::string message_signature;
  asymm::Sign(boost::lexical_cast<std::string>(kStoreRequest) + message,
             *private_key,
             &message_signature);
  return std::make_pair(message, message_signature);
}

}  // namespace dht

}  // namespace maidsafe

#endif  // MAIDSAFE_DHT_RPCS_H_

Added wiki_references/2017/software/MaidSafe_net/src_from_GitHub/the_repository_clones/MaidSafe-DHT/src/maidsafe/dht/rpcs.proto version [99cadca7b2].















































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
import "maidsafe/dht/kademlia.proto";

package maidsafe.dht.protobuf;

message SignedValue {
  required bytes value = 1;
  required bytes signature = 2;
}

message PingRequest {
  required Contact sender = 1;
  required bytes ping = 2;
}

message PingResponse {
  required bytes echo = 1;
}

message FindValueRequest {
  required Contact sender = 1;
  required bytes key = 2;
  optional int32 num_nodes_requested = 3;
}

message FindValueResponse {
  required bool result = 1;
  repeated Contact closest_nodes = 2;
  repeated SignedValue signed_values = 3;
  optional Contact cached_copy_holder = 4;
}

message FindNodesRequest {
  required Contact sender = 1;
  required bytes key = 2;
  optional int32 num_nodes_requested = 3;
}

message FindNodesResponse {
  required bool result = 1;
  repeated Contact closest_nodes = 2;
}

message StoreRequest {
  required Contact sender = 1;
  required bytes key = 2;
  required SignedValue signed_value = 3;
  required int32 ttl = 4;
}

message StoreResponse {
  required bool result = 1;
}

message StoreRefreshRequest {
  required Contact sender = 1;
  optional bytes serialised_store_request = 2;
  optional bytes serialised_store_request_signature = 3;
}

message StoreRefreshResponse {
  required bool result = 1;
}

message DeleteRequest {
  required Contact sender = 1;
  required bytes key = 2;
  required SignedValue signed_value = 3;
}

message DeleteResponse {
  required bool result = 1;
}

message DeleteRefreshRequest {
  required Contact sender = 1;
  optional bytes serialised_delete_request = 2;
  optional bytes serialised_delete_request_signature = 3;
}

message DeleteRefreshResponse {
  required bool result = 1;
}

message DownlistNotification {
  required Contact sender = 1;
  repeated bytes node_ids = 2;
}

Added wiki_references/2017/software/MaidSafe_net/src_from_GitHub/the_repository_clones/MaidSafe-DHT/src/maidsafe/dht/rpcs_objects.cc version [dcc14bc9cf].













































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
/* Copyright (c) 2011 maidsafe.net limited
All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

    * Redistributions of source code must retain the above copyright notice,
    this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright notice,
    this list of conditions and the following disclaimer in the documentation
    and/or other materials provided with the distribution.
    * Neither the name of the maidsafe.net limited nor the names of its
    contributors may be used to endorse or promote products derived from this
    software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include "maidsafe/dht/rpcs_objects.h"

namespace maidsafe {

namespace dht {

ConnectedObjectsList::ConnectedObjectsList()
    : objects_container_(new ConnectedObjectsContainer),
      shared_mutex_(),
      index_(0) {}

ConnectedObjectsList::~ConnectedObjectsList() {}

uint32_t ConnectedObjectsList::AddObject(
    const TransportPtr transport,
    const MessageHandlerPtr message_handler) {
  ConnectedObject object(transport, message_handler, index_);
  UniqueLock unique_lock(shared_mutex_);
  ConnectedObjectsContainer::index<TagIndexId>::type& index_by_index_id =
      objects_container_->get<TagIndexId>();
  index_by_index_id.insert(object);
  uint32_t result = index_;
  // increment the counter
  // TODO(qi.ma@maidsafe.net): should some kind of range check to applied here?
  ++index_;
  return result;
}

bool ConnectedObjectsList::RemoveObject(uint32_t index) {
  UpgradeLock upgrade_lock(shared_mutex_);
  ConnectedObjectsContainer::index<TagIndexId>::type& index_by_index_id =
      objects_container_->get<TagIndexId>();
  auto it = index_by_index_id.find(index);
  if (it == index_by_index_id.end())
    return false;
  UpgradeToUniqueLock unique_lock(upgrade_lock);
  // Remove the entry from multi index
  index_by_index_id.erase(it);
  return true;
}

TransportPtr ConnectedObjectsList::GetTransport(uint32_t index) {
  SharedLock shared_lock(shared_mutex_);
  ConnectedObjectsContainer::index<TagIndexId>::type& index_by_index_id =
      objects_container_->get<TagIndexId>();
  auto it = index_by_index_id.find(index);
  if (it == index_by_index_id.end())
    return TransportPtr();
  return (*it).transport_ptr;
}

size_t ConnectedObjectsList::Size() {
  SharedLock shared_lock(shared_mutex_);
  return objects_container_->size();
}

}  // namespace dht

}  // namespace maidsafe

Added wiki_references/2017/software/MaidSafe_net/src_from_GitHub/the_repository_clones/MaidSafe-DHT/src/maidsafe/dht/rpcs_objects.h version [95cc3eb53c].







































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
/* Copyright (c) 2011 maidsafe.net limited
All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

    * Redistributions of source code must retain the above copyright notice,
    this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright notice,
    this list of conditions and the following disclaimer in the documentation
    and/or other materials provided with the distribution.
    * Neither the name of the maidsafe.net limited nor the names of its
    contributors may be used to endorse or promote products derived from this
    software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#ifndef MAIDSAFE_DHT_RPCS_OBJECTS_H_
#define MAIDSAFE_DHT_RPCS_OBJECTS_H_

#include <cstdint>
#include <string>

#ifdef __MSVC__
#  pragma warning(push)
#  pragma warning(disable: 4244)
#endif
#include "boost/multi_index_container.hpp"
#include "boost/multi_index/composite_key.hpp"
#include "boost/multi_index/ordered_index.hpp"
#include "boost/multi_index/identity.hpp"
#include "boost/multi_index/member.hpp"
#include "boost/multi_index/mem_fun.hpp"
#ifdef __MSVC__
#  pragma warning(pop)
#endif
#include "boost/thread/shared_mutex.hpp"
#include "boost/thread/locks.hpp"
#include "maidsafe/transport/transport.h"

#include "maidsafe/dht/config.h"
#include "maidsafe/dht/message_handler.h"
#include "maidsafe/dht/version.h"

#if MAIDSAFE_DHT_VERSION != 3200
#  error This API is not compatible with the installed library.\
    Please update the maidsafe-dht library.
#endif


namespace maidsafe  {

namespace dht {

struct ConnectedObject {
  ConnectedObject(const TransportPtr transport,
       const MessageHandlerPtr message_handler,
       const uint32_t index)
      : transport_ptr(transport),
        message_handler_ptr(message_handler),
        this_index(index) {}

  TransportPtr transport_ptr;
  MessageHandlerPtr message_handler_ptr;
  uint32_t this_index;
};

struct TagIndexId {};

typedef boost::multi_index::multi_index_container<
  ConnectedObject,
  boost::multi_index::indexed_by<
    boost::multi_index::ordered_unique<
      boost::multi_index::tag<TagIndexId>,
      BOOST_MULTI_INDEX_MEMBER(ConnectedObject, uint32_t, this_index)
    >
  >
> ConnectedObjectsContainer;

// This class temporarily holds the connected objects of Rpcs to ensure all
// resources can be correctly released and no memory leaked
class ConnectedObjectsList  {
 public:
  ConnectedObjectsList();

  ~ConnectedObjectsList();
  // Adds a connected object into the multi index
  // return the index of those objects in the container
  uint32_t AddObject(const TransportPtr transport,
                     const MessageHandlerPtr message_handler);

  // Remove an object based on the index
  // Returns true if successfully removed or false otherwise.
  bool RemoveObject(uint32_t index);

  // Return the TransportPtr of the index
  TransportPtr GetTransport(uint32_t index);

  // Returns the size of the connected objects MI
  size_t Size();

 private:
  typedef boost::shared_lock<boost::shared_mutex> SharedLock;
  typedef boost::upgrade_lock<boost::shared_mutex> UpgradeLock;
  typedef boost::unique_lock<boost::shared_mutex> UniqueLock;
  typedef boost::upgrade_to_unique_lock<boost::shared_mutex>
          UpgradeToUniqueLock;

  /**  Multi_index container of connected objects */
  std::shared_ptr<ConnectedObjectsContainer> objects_container_;
  /** Thread safe shared mutex */
  boost::shared_mutex shared_mutex_;
  /** Global Counter used as an index for each added object */
  uint32_t index_;
};

}  // namespace dht

}  // namespace maidsafe

#endif  // MAIDSAFE_DHT_RPCS_OBJECTS_H_

Added wiki_references/2017/software/MaidSafe_net/src_from_GitHub/the_repository_clones/MaidSafe-DHT/src/maidsafe/dht/sender_task.cc version [aa2955c232].

































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
/* Copyright (c) 2011 maidsafe.net limited
All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

    * Redistributions of source code must retain the above copyright notice,
    this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright notice,
    this list of conditions and the following disclaimer in the documentation
    and/or other materials provided with the distribution.
    * Neither the name of the maidsafe.net limited nor the names of its
    contributors may be used to endorse or promote products derived from this
    software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include "maidsafe/dht/sender_task.h"

#include "maidsafe/dht/log.h"

namespace maidsafe {

namespace dht {

Task::Task(const KeyValueSignature &key_value_signature,
           const transport::Info &info,
           const RequestAndSignature &request_signature,
           const std::string &public_key_id,
           TaskCallback ops_callback)
    : key_value_signature(key_value_signature),
      info(info),
      request_signature(request_signature),
      public_key_id(public_key_id),
      ops_callback(ops_callback) {}

const std::string& Task::key() const {
  return key_value_signature.key;
}

const asymm::Identity& Task::get_public_key_id() const {
  return public_key_id;
}

SenderTask::SenderTask()
    : task_index_(new TaskIndex),
      shared_mutex_() {}

SenderTask::~SenderTask() {}

bool SenderTask::AddTask(const KeyValueSignature &key_value_signature,
                         const transport::Info &info,
                         const RequestAndSignature &request_signature,
                         const asymm::Identity &public_key_id,
                         TaskCallback ops_callback,
                         bool *is_new_id) {
  if (key_value_signature.key.empty()) {
    DLOG(WARNING) << "Empty key.";
    return false;
  }
  if (key_value_signature.value.empty()) {
    DLOG(WARNING) << "Empty value.";
    return false;
  }
  if (key_value_signature.signature.empty()) {
    DLOG(WARNING) << "Empty signature.";
    return false;
  }
  if (public_key_id.empty()) {
    DLOG(WARNING) << "Empty public_key_id.";
    return false;
  }
  if (request_signature.first.empty()) {
    DLOG(WARNING) << "Empty request.";
    return false;
  }
  if (!ops_callback) {
    DLOG(WARNING) << "Invalid callback.";
    return false;
  }

  Task task(key_value_signature, info, request_signature, public_key_id,
            ops_callback);
  UpgradeLock upgrade_lock(shared_mutex_);
  TaskIndex::index<TagPublicKeyId>::type& index_by_public_key_id =
      task_index_->get<TagPublicKeyId>();

  auto it = index_by_public_key_id.find(public_key_id);
  *is_new_id = (it == index_by_public_key_id.end());

  TaskIndex::index<TagTaskKey>::type& index_by_key =
      task_index_->get<TagTaskKey>();
  auto itr = index_by_key.find(key_value_signature.key);
  if (itr != index_by_key.end()) {
    if ((*itr).public_key_id != public_key_id) {
      DLOG(WARNING) << "Stored key is associated with different public_key_id.";
      return false;
    }
  }
  UpgradeToUniqueLock unique_lock(upgrade_lock);
  auto itr_return = index_by_public_key_id.insert(task);
#ifdef DEBUG
  if (!itr_return.second)
      DLOG(WARNING) << "Task already exists.";
#endif
  return itr_return.second;
}

void SenderTask::SenderTaskCallback(
    asymm::Identity public_key_id,
    asymm::PublicKey public_key,
    asymm::ValidationToken public_key_validation) {
  if (public_key_id.empty()) {
    DLOG(WARNING) << "Empty public_key_id.";
    return;
  }
  UpgradeLock upgrade_lock(shared_mutex_);
  TaskIndex::index<TagPublicKeyId>::type& index_by_public_key_id =
      task_index_->get<TagPublicKeyId>();
  auto itr_pair = index_by_public_key_id.equal_range(public_key_id);
  UpgradeToUniqueLock unique_lock(upgrade_lock);
  while (itr_pair.first != itr_pair.second) {
    TaskCallback call_back = (*itr_pair.first).ops_callback;
    call_back((*itr_pair.first).key_value_signature, (*itr_pair.first).info,
              (*itr_pair.first).request_signature, public_key,
              public_key_validation);
    // Remove entry from multi index
    index_by_public_key_id.erase(itr_pair.first++);
  }
}

}  // namespace dht

}  // namespace maidsafe

Added wiki_references/2017/software/MaidSafe_net/src_from_GitHub/the_repository_clones/MaidSafe-DHT/src/maidsafe/dht/sender_task.h version [e608cd4bc7].



































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
/* Copyright (c) 2011 maidsafe.net limited
All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

    * Redistributions of source code must retain the above copyright notice,
    this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright notice,
    this list of conditions and the following disclaimer in the documentation
    and/or other materials provided with the distribution.
    * Neither the name of the maidsafe.net limited nor the names of its
    contributors may be used to endorse or promote products derived from this
    software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#ifndef MAIDSAFE_DHT_SENDER_TASK_H_
#define MAIDSAFE_DHT_SENDER_TASK_H_

#include <functional>
#include <string>

#include "maidsafe/transport/transport.h"
#include "maidsafe/dht/data_store.h"

namespace maidsafe  {

namespace dht {

namespace test {
class SenderTaskTest;
class ServicesTest;
class SenderTaskTest_BEH_AddTask_Test;
class SenderTaskTest_FUNC_SenderTaskCallback_Test;
class SenderTaskTest_FUNC_SenderTaskCallbackMultiThreaded_Test;
}

class Service;

typedef std::function<void(KeyValueSignature,
                           transport::Info,
                           RequestAndSignature,
                           asymm::PublicKey,
                           asymm::ValidationToken)> TaskCallback;

struct Task {
  Task(const KeyValueSignature &key_value_signature,
       const transport::Info &info,
       const RequestAndSignature &request_signature,
       const std::string &public_key_id,
       TaskCallback ops_callback);

  const std::string& key() const;
  const asymm::Identity& get_public_key_id() const;

  KeyValueSignature key_value_signature;
  transport::Info info;
  RequestAndSignature request_signature;
  asymm::Identity public_key_id;
  TaskCallback ops_callback;
};

struct TagPublicKeyId {};
struct TagTaskKey {};

typedef boost::multi_index::multi_index_container<
  Task,
  boost::multi_index::indexed_by<
    boost::multi_index::ordered_non_unique<
      boost::multi_index::tag<TagTaskKey>,
      BOOST_MULTI_INDEX_CONST_MEM_FUN(Task, const std::string&, key)
    >,
    boost::multi_index::ordered_non_unique<
      boost::multi_index::tag<TagPublicKeyId>,
      BOOST_MULTI_INDEX_CONST_MEM_FUN(Task, const asymm::Identity&,
                                      get_public_key_id)
    >
  >
> TaskIndex;
// This class temporarily holds the tasks of Service and reduces the number of
// network lookup for same requester.
class SenderTask  {
 public:
  SenderTask();

  ~SenderTask();
  // Adds a task into the multi index and executes it when the
  // SenderTaskCallback() is called after network lookup for a given sender.
  // Doesn't store task if provided key is already stored and is associated
  // with different public_key_id.
  // Modifies is_new_id to true if it is a task by the sender whose
  // public_key_id is not present in the  multi index.
  // Returns false if stored key is associated with different public_key_id.
  // Returns true if successfully added into the multi index or false otherwise.
  bool AddTask(const KeyValueSignature &key_value_signature,
               const transport::Info &info,
               const RequestAndSignature &request_signature,
               const asymm::Identity &public_key_id,
               TaskCallback ops_callback,
               bool *is_new_id);

 private:
  friend class Service;
  friend class test::SenderTaskTest;
  friend class test::ServicesTest;
  friend class test::SenderTaskTest_BEH_AddTask_Test;
  friend class test::SenderTaskTest_FUNC_SenderTaskCallback_Test;
  friend class test::SenderTaskTest_FUNC_SenderTaskCallbackMultiThreaded_Test;

  typedef boost::shared_lock<boost::shared_mutex> SharedLock;
  typedef boost::upgrade_lock<boost::shared_mutex> UpgradeLock;
  typedef boost::unique_lock<boost::shared_mutex> UniqueLock;
  typedef boost::upgrade_to_unique_lock<boost::shared_mutex>
          UpgradeToUniqueLock;

  // Executes all the tasks present in the multi index under given
  // public_key_id and delete them from the multi index after the execution.
  // Does nothing if the public_key_id is empty or task for given public_key_id
  // is not present in the multi index.
  void SenderTaskCallback(asymm::Identity public_key_id,
                          asymm::PublicKey public_key,
                          asymm::ValidationToken public_key_validation);

  /**  Multi_index container of sender tasks */
  std::shared_ptr<TaskIndex> task_index_;
  /** Thread safe shared mutex */
  boost::shared_mutex shared_mutex_;
};

}  // namespace dht

}  // namespace maidsafe

#endif  // MAIDSAFE_DHT_SENDER_TASK_H_

Added wiki_references/2017/software/MaidSafe_net/src_from_GitHub/the_repository_clones/MaidSafe-DHT/src/maidsafe/dht/service.cc version [268d819c35].

















































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
/* Copyright (c) 2009 maidsafe.net limited
All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

    * Redistributions of source code must retain the above copyright notice,
    this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright notice,
    this list of conditions and the following disclaimer in the documentation
    and/or other materials provided with the distribution.
    * Neither the name of the maidsafe.net limited nor the names of its
    contributors may be used to endorse or promote products derived from this
    software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include <utility>
#include <set>

#include "maidsafe/dht/service.h"

#include "maidsafe/common/crypto.h"

#ifdef __MSVC__
#  pragma warning(push)
#  pragma warning(disable: 4127 4244 4267)
#endif
#include "maidsafe/dht/rpcs.pb.h"
#ifdef __MSVC__
#  pragma warning(pop)
#endif
#include "maidsafe/dht/message_handler.h"
#include "maidsafe/dht/return_codes.h"
#include "maidsafe/dht/routing_table.h"
#include "maidsafe/dht/utils.h"
#include "maidsafe/dht/log.h"


namespace args = std::placeholders;

namespace maidsafe {

namespace dht {

Service::Service(std::shared_ptr<RoutingTable> routing_table,
                 std::shared_ptr<DataStore> data_store,
                 PrivateKeyPtr private_key,
                 const uint16_t &k)
    : routing_table_(routing_table),
      datastore_(data_store),
      private_key_(private_key),
      node_joined_(false),
      node_contact_(),
      k_(k),
      sender_task_(new SenderTask),
      client_node_id_(NodeId().String()),
      contact_validation_getter_(std::bind(&StubContactValidationGetter,
                                           args::_1, args::_2)),
      contact_validator_(std::bind(&StubContactValidator, args::_1, args::_2,
                                   args::_3)),
      validate_functor_(std::bind(&StubValidate, args::_1, args::_2,
                                  args::_3)),
      check_cache_functor_() {}

Service::~Service() {}

void Service::ConnectToSignals(MessageHandlerPtr message_handler) {
  // Connect service to message handler for incoming parsed requests
  message_handler->on_ping_request()->connect(
      MessageHandler::PingReqSigPtr::element_type::slot_type(
          &Service::Ping, this, _1, _2, _3, _4).track_foreign(
              shared_from_this()));
  message_handler->on_find_value_request()->connect(
      MessageHandler::FindValueReqSigPtr::element_type::slot_type(
          &Service::FindValue, this, _1, _2, _3, _4).track_foreign(
              shared_from_this()));
  message_handler->on_find_nodes_request()->connect(
      MessageHandler::FindNodesReqSigPtr::element_type::slot_type(
          &Service::FindNodes, this, _1, _2, _3, _4).track_foreign(
              shared_from_this()));
  message_handler->on_store_request()->connect(
      MessageHandler::StoreReqSigPtr::element_type::slot_type(
          &Service::Store, this, _1, _2, _3, _4, _5, _6).track_foreign(
              shared_from_this()));
  message_handler->on_store_refresh_request()->connect(
      MessageHandler::StoreRefreshReqSigPtr::element_type::slot_type(
          &Service::StoreRefresh, this, _1, _2, _3, _4).track_foreign(
              shared_from_this()));
  message_handler->on_delete_request()->connect(
      MessageHandler::DeleteReqSigPtr::element_type::slot_type(
          &Service::Delete, this, _1, _2, _3, _4, _5, _6).track_foreign(
              shared_from_this()));
  message_handler->on_delete_refresh_request()->connect(
      MessageHandler::DeleteRefreshReqSigPtr::element_type::slot_type(
          &Service::DeleteRefresh, this, _1, _2, _3, _4).track_foreign(
              shared_from_this()));
  message_handler->on_downlist_notification()->connect(
      MessageHandler::DownlistNtfSigPtr::element_type::slot_type(
          &Service::Downlist, this, _1, _2, _3).track_foreign(
              shared_from_this()));
}

bool Service::CheckParameters(const std::string &method_name,
                              const Key *key,
                              const std::string *message,
                              const std::string *message_signature) const {
  std::string debug_msg(DebugId(node_contact_) + " - in " + method_name + ": ");
  if (!node_joined_) {
    DLOG(WARNING) << debug_msg << ": Not joined.";
    return false;
  }
  if (!private_key_) {
    DLOG(WARNING) << debug_msg << ": nullptr private_key.";
    return false;
  }
  if (key && !key->IsValid()) {
    DLOG(WARNING) << debug_msg << ": invalid Kad key.";
    return false;
  }
  if (message && message->empty()) {
    DLOG(WARNING) << debug_msg << ": empty message.";
    return false;
  }
  if (message_signature && message_signature->empty()) {
    DLOG(WARNING) << debug_msg << "signature empty.";
    return false;
  }
  return true;
}

void Service::Ping(const transport::Info &info,
                   const protobuf::PingRequest &request,
                   protobuf::PingResponse *response,
                   transport::Timeout*) {
  response->set_echo("");
  if (!CheckParameters("Ping", nullptr, &request.ping()))
    return;
  response->set_echo(request.ping());
  DLOG(INFO) << "\t" << DebugId(node_contact_) << " PING from "
             << DebugId(FromProtobuf(request.sender()));
  AddContactToRoutingTable(FromProtobuf(request.sender()), info);
}

void Service::FindValue(const transport::Info &info,
                        const protobuf::FindValueRequest &request,
                        protobuf::FindValueResponse *response,
                        transport::Timeout*) {
  response->set_result(false);
  Key key(request.key());
  if (!CheckParameters("FindValue", &key))
    return;

  Contact sender(FromProtobuf(request.sender()));

  // Do we have the value stored outside of the DataStore?
  if (check_cache_functor_ && check_cache_functor_(key.String())) {
    *(response->mutable_cached_copy_holder()) = ToProtobuf(node_contact_);
    response->set_result(true);
    AddContactToRoutingTable(sender, info);
    return;
  }

  // Do we have the values?
  std::vector<ValueAndSignature> values_and_signatures;
  if (datastore_->GetValues(key.String(), &values_and_signatures)) {
    for (unsigned int i = 0; i < values_and_signatures.size(); i++) {
      protobuf::SignedValue *signed_value = response->add_signed_values();
      signed_value->set_value(values_and_signatures[i].first);
      signed_value->set_signature(values_and_signatures[i].second);
    }
    response->set_result(true);
    AddContactToRoutingTable(sender, info);
    return;
  }

  size_t num_nodes_requested(k_);
  if (request.has_num_nodes_requested() && request.num_nodes_requested() > k_)
    num_nodes_requested = request.num_nodes_requested();

  std::vector<Contact> closest_contacts, exclude_contacts;
  routing_table_->GetCloseContacts(key, num_nodes_requested,
                                   exclude_contacts, &closest_contacts);
  for (size_t i = 0; i < closest_contacts.size(); ++i)
    (*response->add_closest_nodes()) = ToProtobuf(closest_contacts[i]);

  response->set_result(true);
  AddContactToRoutingTable(sender, info);
}

void Service::FindNodes(const transport::Info &info,
                        const protobuf::FindNodesRequest &request,
                        protobuf::FindNodesResponse *response,
                        transport::Timeout*) {
  response->set_result(false);
  Key key(request.key());
  if (!CheckParameters("FindNodes", &key))
    return;

  size_t num_nodes_requested(k_);
  if (request.has_num_nodes_requested() && request.num_nodes_requested() > k_)
    num_nodes_requested = request.num_nodes_requested();

  std::vector<Contact> closest_contacts, exclude_contacts;
  routing_table_->GetCloseContacts(key, num_nodes_requested, exclude_contacts,
                                   &closest_contacts);
  for (size_t i = 0; i < closest_contacts.size(); ++i)
    *response->add_closest_nodes() = ToProtobuf(closest_contacts[i]);
  response->set_result(true);

  Contact sender(FromProtobuf(request.sender()));
  if (sender.node_id().String() != client_node_id_) {
    routing_table_->AddContact(FromProtobuf(request.sender()),
                               RankInfoPtr(new transport::Info(info)));
  }
}

void Service::Store(const transport::Info &info,
                    const protobuf::StoreRequest &request,
                    const std::string &message,
                    const std::string &message_signature,
                    protobuf::StoreResponse *response,
                    transport::Timeout*) {
  response->set_result(false);
  Key key(request.key());
  if (!CheckParameters("Store", &key, &message, &message_signature))
    return;

  // Check if same private key signs other values under same key in datastore
  KeyValueSignature key_value_signature(key.String(),
                                        request.signed_value().value(),
                                        request.signed_value().signature());
  asymm::PublicKey sender_public_key;
  asymm::DecodePublicKey(request.sender().public_key(), &sender_public_key);
  if (datastore_->DifferentSigner(key_value_signature, sender_public_key)) {
    DLOG(WARNING) << DebugId(node_contact_) << ": Can't store - different "
                  << "signing key used to store under Kad key.";
    routing_table_->AddContact(FromProtobuf(request.sender()),
                               RankInfoPtr(new transport::Info(info)));
    return;
  }

  RequestAndSignature request_signature(message, message_signature);
  TaskCallback store_cb = std::bind(&Service::StoreCallback, this, args::_1,
                              request, args::_2, args::_3, args::_4, args::_5);
  bool is_new_id = true;
  if (sender_task_->AddTask(key_value_signature, info, request_signature,
                            request.sender().public_key_id(), store_cb,
                            &is_new_id)) {
    if (is_new_id) {  // If public_key_id is new
      asymm::Identity id(request.sender().public_key_id());
      asymm::GetPublicKeyAndValidationCallback callback(std::bind(
          &SenderTask::SenderTaskCallback, sender_task_, id, args::_1,
          args::_2));
      contact_validation_getter_(id, callback);
    }
    response->set_result(true);
  } else {
    DLOG(ERROR) << DebugId(node_contact_) << ": failed to add the store task.";
  }
}

void Service::StoreRefresh(const transport::Info &info,
                           const protobuf::StoreRefreshRequest &request,
                           protobuf::StoreRefreshResponse *response,
                           transport::Timeout*) {
  response->set_result(false);
  if (!CheckParameters("StoreRefresh", nullptr,
                       &request.serialised_store_request(),
                       &request.serialised_store_request_signature()))
    return;

  protobuf::StoreRequest ori_store_request;
  if (!ori_store_request.ParseFromString(request.serialised_store_request())) {
    DLOG(WARNING) << DebugId(node_contact_) << ": Invalid serialised store "
                  << "request.";
    return;
  }

  if (!Key(ori_store_request.key()).IsValid()) {
    DLOG(WARNING) << DebugId(node_contact_) << ": Invalid key.";
    return;
  }

  // Check if same private key signs other values under same key in datastore
  KeyValueSignature key_value_signature(
      ori_store_request.key(), ori_store_request.signed_value().value(),
      ori_store_request.signed_value().signature());
  asymm::PublicKey sender_public_key;
  asymm::DecodePublicKey(ori_store_request.sender().public_key(),
                        &sender_public_key);
  if (datastore_->DifferentSigner(key_value_signature, sender_public_key)) {
    DLOG(WARNING) << DebugId(node_contact_) << ": Can't refresh store - "
                  << "different signing key used to store under Kad key.";
    routing_table_->AddContact(FromProtobuf(request.sender()),
                               RankInfoPtr(new transport::Info(info)));
    return;
  }

  RequestAndSignature request_signature(request.serialised_store_request(),
                          request.serialised_store_request_signature());
  TaskCallback store_refresh_cb = std::bind(&Service::StoreRefreshCallback,
                                            this, args::_1, request, args::_2,
                                            args::_3, args::_4, args::_5);
  bool is_new_id = true;
  if (sender_task_->AddTask(key_value_signature, info, request_signature,
                            ori_store_request.sender().public_key_id(),
                            store_refresh_cb, &is_new_id)) {
    if (is_new_id) {
      asymm::GetPublicKeyAndValidationCallback callback(
          std::bind(&SenderTask::SenderTaskCallback, sender_task_,
                    ori_store_request.sender().public_key_id(), args::_1,
                    args::_2));
      contact_validation_getter_(ori_store_request.sender().public_key_id(),
                                 callback);
    }
    response->set_result(true);
  } else {
    DLOG(ERROR) << DebugId(node_contact_) << ": failed to add the store "
                << "refresh task.";
  }
}

void Service::StoreCallback(KeyValueSignature key_value_signature,
                            protobuf::StoreRequest request,
                            transport::Info info,
                            RequestAndSignature request_signature,
                            asymm::PublicKey public_key,
                            asymm::ValidationToken public_key_validation) {
  if (ValidateAndStore(key_value_signature, request, info, request_signature,
                       public_key, public_key_validation, false))
    if (request.sender().node_id() != client_node_id_)
      routing_table_->AddContact(FromProtobuf(request.sender()),
                                 RankInfoPtr(new transport::Info(info)));
}

void Service::StoreRefreshCallback(
    KeyValueSignature key_value_signature,
    protobuf::StoreRefreshRequest request,
    transport::Info info,
    RequestAndSignature request_signature,
    asymm::PublicKey public_key,
    asymm::ValidationToken public_key_validation) {
  protobuf::StoreRequest ori_store_request;
  ori_store_request.ParseFromString(request.serialised_store_request());
  if (ValidateAndStore(key_value_signature, ori_store_request, info,
      request_signature, public_key, public_key_validation, true))
    if (request.sender().node_id() != client_node_id_)
      routing_table_->AddContact(FromProtobuf(request.sender()),
                                 RankInfoPtr(new transport::Info(info)));
}

bool Service::ValidateAndStore(
    const KeyValueSignature &key_value_signature,
    const protobuf::StoreRequest &request,
    const transport::Info &/*info*/,
    const RequestAndSignature &request_signature,
    const asymm::PublicKey &public_key,
    const asymm::ValidationToken &public_key_validation,
    const bool is_refresh) {
  if (!contact_validator_(request.sender().public_key_id(), public_key,
                          public_key_validation)) {
    DLOG(WARNING) << DebugId(node_contact_) << ": Failed to validate contact "
                  << " for Store request (is_refresh = " << std::boolalpha
                  << is_refresh << ")";
    return false;
  }
  if (!validate_functor_(key_value_signature.value,
                         key_value_signature.signature,
                         public_key)) {
    DLOG(WARNING) << DebugId(node_contact_) << ": Failed to validate Store "
                  << "request for kademlia value (is_refresh = "
                  << std::boolalpha << is_refresh << ")";
    return false;
  }
  if (is_refresh && !validate_functor_(request_signature.first,
                                       request_signature.second,
                                       public_key)) {
    DLOG(WARNING) << DebugId(node_contact_) << ": Failed to validate request "
                  << "against request signature";
    return false;
  }
  if (datastore_->StoreValue(key_value_signature,
      boost::posix_time::seconds(request.ttl()), request_signature,
      is_refresh) == kSuccess) {
    return true;
  } else {
    DLOG(WARNING) << DebugId(node_contact_) << ": Failed to store Kad value.";
    return false;
  }
}

void Service::Delete(const transport::Info &info,
                     const protobuf::DeleteRequest &request,
                     const std::string &message,
                     const std::string &message_signature,
                     protobuf::DeleteResponse *response,
                     transport::Timeout*) {
  response->set_result(false);
  Key key(request.key());
  if (!CheckParameters("Delete", &key, &message, &message_signature))
    return;

  if (!datastore_->HasKey(key.String())) {
    response->set_result(true);
    return;
  }

  // Check if same private key signs other values under same key in datastore
  KeyValueSignature key_value_signature(key.String(),
                                        request.signed_value().value(),
                                        request.signed_value().signature());
  asymm::PublicKey sender_public_key;
  asymm::DecodePublicKey(request.sender().public_key(), &sender_public_key);
  if (datastore_->DifferentSigner(key_value_signature, sender_public_key)) {
    DLOG(WARNING) << DebugId(node_contact_) << ": Can't delete - different "
                  << "signing key used to store key,value.";
    routing_table_->AddContact(FromProtobuf(request.sender()),
                               RankInfoPtr(new transport::Info(info)));
    return;
  }

  RequestAndSignature request_signature(message, message_signature);
  TaskCallback delete_cb = std::bind(&Service::DeleteCallback, this, args::_1,
                                     request, args::_2, args::_3, args::_4,
                                     args::_5);
  bool is_new_id = true;
  if (sender_task_->AddTask(key_value_signature, info, request_signature,
                            request.sender().public_key_id(), delete_cb,
                            &is_new_id)) {
    if (is_new_id) {
      asymm::GetPublicKeyAndValidationCallback callback(
          std::bind(&SenderTask::SenderTaskCallback, sender_task_,
                    request.sender().public_key_id(), args::_1, args::_2));
      contact_validation_getter_(request.sender().public_key_id(), callback);
    }
    response->set_result(true);
  } else {
    DLOG(ERROR) << DebugId(node_contact_) << ": failed to add the delete task.";
  }
}

void Service::DeleteRefresh(const transport::Info &info,
                            const protobuf::DeleteRefreshRequest &request,
                            protobuf::DeleteRefreshResponse *response,
                            transport::Timeout*) {
  response->set_result(false);
  if (!CheckParameters("DeleteRefresh", nullptr,
                       &request.serialised_delete_request(),
                       &request.serialised_delete_request_signature()))
    return;

  protobuf::DeleteRequest ori_delete_request;
  if (!ori_delete_request.ParseFromString(
      request.serialised_delete_request())) {
    DLOG(WARNING) << DebugId(node_contact_) << ": Invalid serialised delete "
                  << "request.";
    return;
  }

  if (!Key(ori_delete_request.key()).IsValid()) {
    DLOG(WARNING) << DebugId(node_contact_) << ": Invalid key.";
    return;
  }

  // Check if same private key signs other values under same key in datastore
  KeyValueSignature key_value_signature(
      ori_delete_request.key(),
      ori_delete_request.signed_value().value(),
      ori_delete_request.signed_value().signature());
  asymm::PublicKey sender_public_key;
  asymm::DecodePublicKey(ori_delete_request.sender().public_key(),
                        &sender_public_key);
  if (datastore_->DifferentSigner(key_value_signature, sender_public_key)) {
    DLOG(WARNING) << DebugId(node_contact_) <&l