aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.am2
-rw-r--r--README48
-rwxr-xr-xbootstrap1
-rw-r--r--configure.ac105
-rw-r--r--doc/.latexmkrc15
-rw-r--r--doc/Makefile45
-rw-r--r--doc/fig/svg/ip_map.svg280
-rw-r--r--doc/fig/svg/job_startup.svg520
-rw-r--r--doc/msh.tex368
-rw-r--r--doc/related_work.bib1466
-rw-r--r--src/Makefile.am40
-rw-r--r--src/addressmap.c764
-rw-r--r--src/addressmap.h329
-rw-r--r--src/bitmap.c159
-rw-r--r--src/bitmap.h80
-rw-r--r--src/common.h39
-rw-r--r--src/launch.c44
-rw-r--r--src/launch_ll.c47
-rw-r--r--src/mping.c424
-rw-r--r--src/msh.c938
-rw-r--r--src/msh_waiter.c392
-rw-r--r--src/mshd.c1550
-rw-r--r--src/mshd.h44
-rw-r--r--src/mshd2.c1297
-rw-r--r--src/mtypes.h317
-rw-r--r--src/pmonitor.c314
-rw-r--r--src/pmonitor.h90
-rw-r--r--src/prop.c17
-rw-r--r--src/reduce.c121
-rw-r--r--src/reduce.h21
-rwxr-xr-xsrc/run.sh6
-rw-r--r--src/server.c1248
-rw-r--r--src/server.h56
-rw-r--r--src/test_addressmap.c164
-rw-r--r--src/test_bitmap.c54
-rwxr-xr-xsrc/test_mping.sh12
-rw-r--r--src/test_pty.c666
-rw-r--r--src/ttymodes.c484
-rw-r--r--src/ttymodes.h175
-rw-r--r--src/util.c101
-rw-r--r--src/util.h43
41 files changed, 12886 insertions, 0 deletions
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..647d20b
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,2 @@
1# This Makefile.am is in the public domain
2SUBDIRS = src \ No newline at end of file
diff --git a/README b/README
new file mode 100644
index 0000000..0575a3d
--- /dev/null
+++ b/README
@@ -0,0 +1,48 @@
1MPI-Shell (MSH) is a remote shell for executing commands remotely on hosts where
2Message Passing Interface (MPI) layer is available for communication. Such
3hosts are commonly found in High Performance Computing (HPC) systems such as
4compute clusters or supercomputers.
5
6The motivation for this project is that often in such systems Secure-Shell (SSH)
7is either unavailable or restricted for users due to security reasons. As a
8result, hosts in these systems cannot be used for non MPI applications such as
9network emulators or testbeds which rely on SSH to establish connections among
10the hosts. MSH aims to solve this problem by providing an alternative remote
11shell which can be used by these applications instead of SSH.
12
13Architecture
14------------
15
16MSH consists of two components: the MSH daemon(mshd) and the MSH client. mshd
17is similar to SSH daemon(ssd) in that one mshd instance is started per host.
18The daemons execute the commands given from remote MSH clients. However, unlike
19sshd, mshd is started by the job scheduler employed in the HPC system and only
20runs during the life-time of the job.
21
22
23The MSH client, takes the IP address of the target host and the
24remote command string as arguments. The client relies on the local
25mshd for learning the port address of the remote mshd and for
26authenticating itself to the remote mshd.
27
28The command string is executed by the remote mshd after successful
29authentication of the connecting MSH client. The input for the executed command
30string is relayed by the MSH client to the remote mshd. Similarly, the output
31from the executed command string is relayed from the remote mshd to the MSH
32client;
33
34Installation
35------------
36
37Installation should be fairly simple if you want to go-ahead with the default
38settings. The following steps should do the job:
39
40$ ./bootstrap
41$ ./configure
42$ make
43$ make install
44
45You may change some of the default settings before installing via ./configure.
46For help on those settings and how to change them execute:
47
48./configure --help
diff --git a/bootstrap b/bootstrap
new file mode 100755
index 0000000..dba0b02
--- /dev/null
+++ b/bootstrap
@@ -0,0 +1 @@
autoreconf -if
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000..dba09e6
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,105 @@
1
2# -*- Autoconf -*-
3# Process this file with autoconf to produce a configure script.
4
5AC_PREREQ([2.69])
6AC_INIT([msh], [0.0.0], [totakura@in.tum.de])
7AM_INIT_AUTOMAKE([foreign -Wall -Werror])
8dnl m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
9AC_CONFIG_SRCDIR([src/mshd.c])
10AC_CONFIG_HEADERS([config.h])
11
12# Checks for programs.
13CC=""
14AC_PROG_CC([mpicc])
15AM_PROG_CC_C_O dnl allow per target automake flags
16
17# Checks for header files.
18AC_CHECK_HEADERS([stdlib.h string.h unistd.h netinet/in.h net/if.h ifaddrs.h \
19sys/socket.h sys/select.h sys/time.h sys/types.h error.h errno.h limits.h \
20regex.h time.h],,
21 [AC_MSG_ERROR([a required standard UNIX header is missing])])
22
23# Checks for typedefs, structures, and compiler characteristics.
24
25# Checks for library functions.
26AC_FUNC_MALLOC
27AC_FUNC_REALLOC
28AC_CHECK_FUNCS([strdup strlen strerror strcmp getnameinfo getifaddrs freeifaddrs \
29printf fprintf snprintf vsnprintf memset gettimeofday localtime strftime \
30getpid getcwd],,
31 [AC_MSG_ERROR([a required C library function is missing])])
32
33# test for math functions
34AC_CHECK_HEADERS([math.h],
35 [AC_CHECK_LIB([m], [log])])
36AC_CHECK_FUNC([ceil],math=1)
37if test "$math" != 1
38then
39 AC_MSG_ERROR([MSH requires math library])
40fi
41
42# test for mpi
43AC_CHECK_HEADERS([mpi.h], [AC_CHECK_LIB([mpi], [MPI_Init], [mpi=1])])
44if test "$mpi" != 1
45then
46 AC_MSG_ERROR([MSH requires MPI libraries])
47fi
48
49# test for libgnunetutil
50libgnunetutil=0
51AC_MSG_CHECKING(for libgnunetutil)
52AC_ARG_WITH(gnunet,
53 [AS_HELP_STRING([--with-gnunet=PFX], [base of gnunet installation])],
54 [AC_MSG_RESULT([$with_gnunet])
55 case $with_gnunet in
56 no)
57 ;;
58 yes)
59 AC_CHECK_HEADERS([gnunet/platform.h gnunet/gnunet_util_lib.h],
60 [AC_CHECK_LIB([gnunetutil], [GNUNET_SCHEDULER_run], libgnunetutil=1)],
61 [],
62 [
63 #ifdef HAVE_GNUNET_PLATFORM_H
64 #include <gnunet/platform.h>
65 #endif
66 ])
67 ;;
68 *)
69 LDFLAGS="-L$with_gnunet/lib $LDFLAGS"
70 CPPFLAGS="-I$with_gnunet/include $CPPFLAGS"
71 AC_CHECK_HEADERS([gnunet/platform.h gnunet/gnunet_util_lib.h],
72 [AC_CHECK_LIB([gnunetutil], [GNUNET_SCHEDULER_run],
73 [GNUNET_LDFLAGS="-L$with_gnunet/lib"
74 GNUNET_CPPFLAGS="-I$with_gnunet/include"
75 libgnunetutil=1])],
76 [],
77 [
78 #ifdef HAVE_GNUNET_PLATFORM_H
79 #include <gnunet/platform.h>
80 #endif
81 ])
82 ;;
83 esac
84 ],
85 [AC_MSG_RESULT([--with-gnunet not specified])
86 AC_CHECK_HEADERS([gnunet/platform.h gnunet/gnunet_util_lib.h],
87 [AC_CHECK_LIB([gnunetutil], [GNUNET_SCHEDULER_run], libgnunetutil=1)],
88 [], [
89 #ifdef HAVE_GNUNET_PLATFORM_H
90 #include <gnunet/platform.h>
91 #endif
92 ])
93 ])
94if test "$libgnunetutil" != 1
95then
96 AC_MSG_ERROR([MSH requires gnunet])
97fi
98
99dnl have all messages as of now
100extra_logging=1;
101AC_DEFINE_UNQUOTED([GNUNET_EXTRA_LOGGING],[$extra_logging],[1 if extra logging is enabled, 2 for very verbose extra logging, 0 otherwise])
102
103AC_CONFIG_FILES([Makefile
104 src/Makefile])
105AC_OUTPUT
diff --git a/doc/.latexmkrc b/doc/.latexmkrc
new file mode 100644
index 0000000..16bc358
--- /dev/null
+++ b/doc/.latexmkrc
@@ -0,0 +1,15 @@
1add_cus_dep('glo', 'gls', 0, 'run_makeglossaries');
2add_cus_dep('acn', 'acr', 0, 'run_makeglossaries');
3
4sub run_makeglossaries {
5 if ( $silent ) {
6 system "makeglossaries -q '$_[0]'";
7 }
8 else {
9 system "makeglossaries '$_[0]'";
10 };
11}
12
13push @generated_exts, 'glo', 'gls', 'glg';
14push @generated_exts, 'acn', 'acr', 'alg';
15$clean_ext .= ' %R.ist %R.xdy';
diff --git a/doc/Makefile b/doc/Makefile
new file mode 100644
index 0000000..ecf5a3c
--- /dev/null
+++ b/doc/Makefile
@@ -0,0 +1,45 @@
1MAINFILE := msh
2DIA := $(shell find . -iname '*.dia')
3DOT := $(shell find . -iname '*.dot')
4SVG := $(shell find ./fig/svg -iname '*.svg')
5GNUPLOT := $(shell find . -iname '*.gnuplot')
6VIEWERAPP := xdg-open
7
8.PHONY: all pdf clean view
9all: \
10 $(patsubst %.dot,%.pdf,$(DOT)) \
11 $(patsubst %.dia,%.pdf,$(DIA)) \
12 $(patsubst %.gnuplot,%.pdf,$(GNUPLOT)) \
13 $(patsubst %.svg,%.pdf,$(SVG)) \
14 $(patsubst %.svg,%.pdf,$(SVG2)) \
15 pdf
16
17%.pdf: %.dot
18 dot -Tpdf "$<" > "$@"
19
20%.pdf: %.eps
21 epstopdf "$<"
22
23%.eps: %.dia
24 dia -e "$@" -t eps "$<"
25
26%.pdf: %.gnuplot
27 gnuplot "$@"
28
29%.pdf: %.svg
30 inkscape --export-pdf="$@" --export-latex --file="$<"
31
32pdf:
33 latexmk -r .latexmkrc -silent -pdf $(MAINFILE)
34
35view: all
36 $(VIEWERAPP) $(MAINFILE).pdf &
37
38presentation: \
39
40clean:
41 - latexmk -c
42 - find . | egrep ".*((\.(pdfsync|aux|idx|ind|ilg|log|blg|bbl|toc|lof|lot|dvi|tlf|tlt|glo|out|tcp|nlo|nls|glo|gls|acn|acr|alg|glg|ist|loa))|~)$$" | xargs rm
43 - rm -rf $(MAINFILE).run.xml
44 - rm -rf $(patsubst %.svg,%.pdf,$(SVG)) \
45 $(patsubst %.svg,%.pdf_tex,$(SVG)) \ No newline at end of file
diff --git a/doc/fig/svg/ip_map.svg b/doc/fig/svg/ip_map.svg
new file mode 100644
index 0000000..559099a
--- /dev/null
+++ b/doc/fig/svg/ip_map.svg
@@ -0,0 +1,280 @@
1<?xml version="1.0" encoding="UTF-8" standalone="no"?>
2<!-- Created with Inkscape (http://www.inkscape.org/) -->
3
4<svg
5 xmlns:dc="http://purl.org/dc/elements/1.1/"
6 xmlns:cc="http://creativecommons.org/ns#"
7 xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
8 xmlns:svg="http://www.w3.org/2000/svg"
9 xmlns="http://www.w3.org/2000/svg"
10 xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
11 xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
12 width="241.875"
13 height="205.5625"
14 id="svg3079"
15 version="1.1"
16 inkscape:version="0.48.3.1 r9886"
17 sodipodi:docname="ip_map.svg">
18 <defs
19 id="defs3081">
20 <marker
21 inkscape:stockid="Arrow1Mend"
22 orient="auto"
23 refY="0"
24 refX="0"
25 id="Arrow1Mend"
26 style="overflow:visible">
27 <path
28 id="path4014"
29 d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
30 style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
31 transform="matrix(-0.4,0,0,-0.4,-4,0)"
32 inkscape:connector-curvature="0" />
33 </marker>
34 </defs>
35 <sodipodi:namedview
36 id="base"
37 pagecolor="#ffffff"
38 bordercolor="#666666"
39 borderopacity="1.0"
40 inkscape:pageopacity="0.0"
41 inkscape:pageshadow="2"
42 inkscape:zoom="3.959798"
43 inkscape:cx="223.81354"
44 inkscape:cy="94.866244"
45 inkscape:document-units="px"
46 inkscape:current-layer="layer1"
47 showgrid="false"
48 inkscape:window-width="1920"
49 inkscape:window-height="1141"
50 inkscape:window-x="0"
51 inkscape:window-y="27"
52 inkscape:window-maximized="1"
53 fit-margin-top="0"
54 fit-margin-left="0"
55 fit-margin-right="0"
56 fit-margin-bottom="0" />
57 <metadata
58 id="metadata3084">
59 <rdf:RDF>
60 <cc:Work
61 rdf:about="">
62 <dc:format>image/svg+xml</dc:format>
63 <dc:type
64 rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
65 </cc:Work>
66 </rdf:RDF>
67 </metadata>
68 <g
69 inkscape:label="Layer 1"
70 inkscape:groupmode="layer"
71 id="layer1"
72 transform="translate(-50.25,-296.25)">
73 <rect
74 style="fill:#000000;fill-opacity:0.48034937;stroke:#0f0707;stroke-width:1;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
75 id="rect3113"
76 width="9.0913725"
77 height="8.3337584"
78 x="102.53047"
79 y="382.12595" />
80 <g
81 id="g3885"
82 transform="translate(-51.265241,-18.94036)">
83 <text
84 sodipodi:linespacing="125%"
85 id="text3109"
86 y="432.36218"
87 x="131.42857"
88 style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Serif;-inkscape-font-specification:Sans"
89 xml:space="preserve"><tspan
90 y="432.36218"
91 x="131.42857"
92 id="tspan3111"
93 sodipodi:role="line">mshd</tspan></text>
94 <rect
95 y="421.77444"
96 x="111.11678"
97 height="15.909903"
98 width="41.668793"
99 id="rect3883"
100 style="fill:none;stroke:#0f0707;stroke-width:1;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" />
101 </g>
102 <rect
103 style="fill:none;stroke:#0f0707;stroke-width:1;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
104 id="rect3893"
105 width="64.649765"
106 height="58.588848"
107 x="50.760166"
108 y="377.0752" />
109 <rect
110 style="fill:#000000;fill-opacity:0.48034937;stroke:#0f0707;stroke-width:1;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
111 id="rect3113-4"
112 width="9.0913725"
113 height="8.3337584"
114 x="181.32236"
115 y="447.02826" />
116 <g
117 id="g3885-4"
118 transform="translate(84.095196,37.375641)">
119 <text
120 sodipodi:linespacing="125%"
121 id="text3109-0"
122 y="432.36218"
123 x="131.42857"
124 style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Serif;-inkscape-font-specification:Sans"
125 xml:space="preserve"><tspan
126 y="432.36218"
127 x="131.42857"
128 id="tspan3111-6"
129 sodipodi:role="line">mshd</tspan></text>
130 <rect
131 y="421.77444"
132 x="111.11678"
133 height="15.909903"
134 width="41.668793"
135 id="rect3883-4"
136 style="fill:none;stroke:#0f0707;stroke-width:1;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" />
137 </g>
138 <rect
139 style="fill:none;stroke:#0f0707;stroke-width:1;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
140 id="rect3893-4"
141 width="64.649765"
142 height="58.588848"
143 x="177.53429"
144 y="442.73511" />
145 <rect
146 style="fill:#000000;fill-opacity:0.48034937;stroke:#0f0707;stroke-width:1;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
147 id="rect3113-3"
148 width="9.0913725"
149 height="8.3337584"
150 x="194.20183"
151 y="342.22491" />
152 <g
153 id="g3885-45"
154 transform="translate(93.691642,-119.70308)">
155 <text
156 sodipodi:linespacing="125%"
157 id="text3109-8"
158 y="432.36218"
159 x="131.42857"
160 style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Serif;-inkscape-font-specification:Sans"
161 xml:space="preserve"><tspan
162 y="432.36218"
163 x="131.42857"
164 id="tspan3111-2"
165 sodipodi:role="line">mshd</tspan></text>
166 <rect
167 y="421.77444"
168 x="111.11678"
169 height="15.909903"
170 width="41.668793"
171 id="rect3883-7"
172 style="fill:none;stroke:#0f0707;stroke-width:1;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" />
173 </g>
174 <rect
175 style="fill:none;stroke:#0f0707;stroke-width:1.04493999;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
176 id="rect3893-9"
177 width="70.591049"
178 height="58.588848"
179 x="190.41377"
180 y="296.7681" />
181 <text
182 xml:space="preserve"
183 style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Serif;-inkscape-font-specification:Sans"
184 x="95.206879"
185 y="432.63358"
186 id="text3987"
187 sodipodi:linespacing="125%"><tspan
188 sodipodi:role="line"
189 id="tspan3989"
190 x="95.206879"
191 y="432.63358">Host 0</tspan></text>
192 <text
193 xml:space="preserve"
194 style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Serif;-inkscape-font-specification:Sans"
195 x="218.69803"
196 y="494.2529"
197 id="text3991"
198 sodipodi:linespacing="125%"><tspan
199 sodipodi:role="line"
200 id="tspan3993"
201 x="218.69803"
202 y="494.2529">Host i</tspan></text>
203 <text
204 xml:space="preserve"
205 style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Serif;-inkscape-font-specification:Sans"
206 x="234.60793"
207 y="352.32648"
208 id="text3995"
209 sodipodi:linespacing="125%"><tspan
210 sodipodi:role="line"
211 id="tspan3997"
212 x="234.60793"
213 y="352.32648">Host n-i</tspan></text>
214 <path
215 style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:2, 2;stroke-dashoffset:0;marker-end:url(#Arrow1Mend)"
216 d="m 102.27795,410.66278 c 45.13452,-0.53732 71.31067,22.91671 80.8122,34.59772"
217 id="path3999"
218 inkscape:connector-curvature="0"
219 sodipodi:nodetypes="cc" />
220 <path
221 style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:2, 2;stroke-dashoffset:0;marker-end:url(#Arrow1Mend)"
222 d="m 217.1828,458.39249 c 0,0 15.15229,-3.53555 24.24367,-35.60789"
223 id="path4445"
224 inkscape:connector-curvature="0"
225 sodipodi:nodetypes="cc" />
226 <path
227 style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:2, 2;stroke-dashoffset:0;marker-end:url(#Arrow1Mend)"
228 d="m 203.54573,311.41529 c -35.42471,5.93377 -85.13993,36.11772 -95.45941,69.44799"
229 id="path4629"
230 inkscape:connector-curvature="0"
231 sodipodi:nodetypes="cc" />
232 <text
233 xml:space="preserve"
234 style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Serif;-inkscape-font-specification:Sans"
235 x="264.11429"
236 y="418.23892"
237 id="text4831"
238 sodipodi:linespacing="125%"><tspan
239 sodipodi:role="line"
240 id="tspan4833"
241 x="264.11429"
242 y="418.23892">Host i+1</tspan></text>
243 <text
244 xml:space="preserve"
245 style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Serif;-inkscape-font-specification:Sans"
246 x="263.12442"
247 y="393.23764"
248 id="text4835"
249 sodipodi:linespacing="125%"><tspan
250 sodipodi:role="line"
251 id="tspan4837"
252 x="263.12442"
253 y="393.23764">Host n-i-1</tspan></text>
254 <path
255 style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:2, 2;stroke-dashoffset:0;marker-end:url(#Arrow1Mend)"
256 d="M 232.33508,389.70211 C 217.2561,383.94586 206.33995,370.78455 199.50513,352.07393"
257 id="path5023"
258 inkscape:connector-curvature="0"
259 sodipodi:nodetypes="cc" />
260 <rect
261 style="fill:none;stroke:#0f0707;stroke-width:1.05119431;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
262 id="rect5207"
263 width="57.485756"
264 height="11.869292"
265 x="234.10286"
266 y="408.64249" />
267 <rect
268 style="fill:none;stroke:#0f0707;stroke-width:1.03788722;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
269 id="rect5209"
270 width="57.943794"
271 height="12.879445"
272 x="233.57747"
273 y="383.13611" />
274 <path
275 style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0"
276 d="m 261.37697,408.64247 0,-12.37437"
277 id="path5211"
278 inkscape:connector-curvature="0" />
279 </g>
280</svg>
diff --git a/doc/fig/svg/job_startup.svg b/doc/fig/svg/job_startup.svg
new file mode 100644
index 0000000..12026f2
--- /dev/null
+++ b/doc/fig/svg/job_startup.svg
@@ -0,0 +1,520 @@
1<?xml version="1.0" encoding="UTF-8" standalone="no"?>
2<!-- Created with Inkscape (http://www.inkscape.org/) -->
3
4<svg
5 xmlns:dc="http://purl.org/dc/elements/1.1/"
6 xmlns:cc="http://creativecommons.org/ns#"
7 xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
8 xmlns:svg="http://www.w3.org/2000/svg"
9 xmlns="http://www.w3.org/2000/svg"
10 xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
11 xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
12 width="397.59375"
13 height="289.91965"
14 id="svg2"
15 version="1.1"
16 inkscape:version="0.48.3.1 r9886"
17 sodipodi:docname="job_startup.svg">
18 <defs
19 id="defs4">
20 <marker
21 inkscape:stockid="Arrow1Mstart"
22 orient="auto"
23 refY="0"
24 refX="0"
25 id="Arrow1Mstart"
26 style="overflow:visible">
27 <path
28 id="path3802"
29 d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
30 style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
31 transform="matrix(0.4,0,0,0.4,4,0)"
32 inkscape:connector-curvature="0" />
33 </marker>
34 <marker
35 inkscape:stockid="Arrow1Lstart"
36 orient="auto"
37 refY="0"
38 refX="0"
39 id="Arrow1Lstart"
40 style="overflow:visible">
41 <path
42 id="path3796"
43 d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
44 style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
45 transform="matrix(0.8,0,0,0.8,10,0)"
46 inkscape:connector-curvature="0" />
47 </marker>
48 <marker
49 inkscape:stockid="Arrow1Mend"
50 orient="auto"
51 refY="0"
52 refX="0"
53 id="Arrow1Mend"
54 style="overflow:visible">
55 <path
56 id="path3805"
57 d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
58 style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
59 transform="matrix(-0.4,0,0,-0.4,-4,0)"
60 inkscape:connector-curvature="0" />
61 </marker>
62 </defs>
63 <sodipodi:namedview
64 id="base"
65 pagecolor="#ffffff"
66 bordercolor="#666666"
67 borderopacity="1.0"
68 inkscape:pageopacity="0.0"
69 inkscape:pageshadow="2"
70 inkscape:zoom="3.959798"
71 inkscape:cx="177.40865"
72 inkscape:cy="190.59215"
73 inkscape:document-units="px"
74 inkscape:current-layer="layer1"
75 showgrid="false"
76 showguides="true"
77 inkscape:guide-bbox="true"
78 inkscape:snap-midpoints="true"
79 inkscape:window-width="1920"
80 inkscape:window-height="1061"
81 inkscape:window-x="0"
82 inkscape:window-y="2"
83 inkscape:window-maximized="1"
84 fit-margin-top="0"
85 fit-margin-left="0"
86 fit-margin-right="0"
87 fit-margin-bottom="0"
88 inkscape:snap-global="false">
89 <sodipodi:guide
90 orientation="0,1"
91 position="-23.080357,124.91461"
92 id="guide2989" />
93 <sodipodi:guide
94 orientation="1,0"
95 position="84.0625,201.70032"
96 id="guide3012" />
97 <sodipodi:guide
98 orientation="0,1"
99 position="-29.508929,0.27174738"
100 id="guide4452" />
101 <sodipodi:guide
102 orientation="1,0"
103 position="326.20536,186.70032"
104 id="guide4454" />
105 <sodipodi:guide
106 orientation="0,1"
107 position="21.5625,32.771747"
108 id="guide4456" />
109 <sodipodi:guide
110 orientation="0,1"
111 position="-29.866071,190.62889"
112 id="guide6258" />
113 <sodipodi:guide
114 orientation="1,0"
115 position="197.14286,253.21429"
116 id="guide3061" />
117 </sodipodi:namedview>
118 <metadata
119 id="metadata7">
120 <rdf:RDF>
121 <cc:Work
122 rdf:about="">
123 <dc:format>image/svg+xml</dc:format>
124 <dc:type
125 rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
126 <dc:title />
127 </cc:Work>
128 </rdf:RDF>
129 </metadata>
130 <g
131 inkscape:label="Layer 1"
132 inkscape:groupmode="layer"
133 id="layer1"
134 transform="translate(-68.4375,-169.14286)">
135 <text
136 xml:space="preserve"
137 style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Serif;-inkscape-font-specification:Serif"
138 x="144.5"
139 y="382.57648"
140 id="text3014"
141 sodipodi:linespacing="125%"><tspan
142 sodipodi:role="line"
143 id="tspan3016"
144 x="144.5"
145 y="382.57648">Application</tspan></text>
146 <text
147 xml:space="preserve"
148 style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Serif;-inkscape-font-specification:Serif"
149 x="144.5"
150 y="426.36218"
151 id="text3018"
152 sodipodi:linespacing="125%"><tspan
153 sodipodi:role="line"
154 id="tspan3020"
155 x="144.5"
156 y="426.36218">msh</tspan></text>
157 <path
158 style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow1Mend)"
159 d="m 144.5,343.7774 0,26.85662"
160 id="path3022"
161 inkscape:connector-curvature="0"
162 sodipodi:nodetypes="cc" />
163 <path
164 style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow1Mend)"
165 d="m 144.5,387.394 0,26.82533"
166 id="path4236"
167 inkscape:connector-curvature="0"
168 sodipodi:nodetypes="cc" />
169 <text
170 xml:space="preserve"
171 style="font-size:10px;font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Serif;-inkscape-font-specification:Sans Italic"
172 x="148.5"
173 y="357.7193"
174 id="text4420"
175 sodipodi:linespacing="125%"><tspan
176 sodipodi:role="line"
177 id="tspan4422"
178 x="148.5"
179 y="357.7193"
180 style="font-style:normal">4</tspan></text>
181 <text
182 xml:space="preserve"
183 style="font-size:10px;font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Serif;-inkscape-font-specification:Sans Italic"
184 x="151.40085"
185 y="402.89536"
186 id="text4424"
187 sodipodi:linespacing="125%"><tspan
188 sodipodi:role="line"
189 id="tspan4426"
190 x="151.40085"
191 y="402.89536"
192 style="font-style:normal">5</tspan></text>
193 <text
194 xml:space="preserve"
195 style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Serif;-inkscape-font-specification:Serif"
196 x="190"
197 y="452.00507"
198 id="text4430"
199 sodipodi:linespacing="125%"><tspan
200 sodipodi:role="line"
201 id="tspan4432"
202 x="190"
203 y="452.00507"
204 style="font-style:normal;-inkscape-font-specification:Serif">Host 0</tspan></text>
205 <text
206 xml:space="preserve"
207 style="font-size:10px;font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Serif;-inkscape-font-specification:Sans Italic"
208 x="394.64285"
209 y="426.29074"
210 id="text4458"
211 sodipodi:linespacing="125%"><tspan
212 sodipodi:role="line"
213 id="tspan4460"
214 x="394.64285"
215 y="426.29074">cmd</tspan></text>
216 <text
217 xml:space="preserve"
218 style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Serif;-inkscape-font-specification:Serif"
219 x="110.22112"
220 y="333.25507"
221 id="text2985"
222 sodipodi:linespacing="125%"><tspan
223 sodipodi:role="line"
224 x="110.22112"
225 y="333.25507"
226 id="tspan4262"
227 style="text-align:start;text-anchor:start">mshd (master)</tspan></text>
228 <rect
229 style="fill:none;stroke:#0f0707;stroke-width:1;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
230 id="rect4462"
231 width="89.969322"
232 height="25.414677"
233 x="101.97963"
234 y="318.30737" />
235 <rect
236 style="fill:none;stroke:#0f0707;stroke-width:1;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
237 id="rect4464"
238 width="70.584412"
239 height="14.268419"
240 x="109.5565"
241 y="372.52951"
242 ry="0" />
243 <rect
244 style="fill:none;stroke:#0f0707;stroke-width:1;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
245 id="rect4462-5"
246 width="46.68111"
247 height="14.80503"
248 x="120.98088"
249 y="416.38824" />
250 <rect
251 style="fill:none;stroke:#0f0707;stroke-width:1;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
252 id="rect4462-55"
253 width="85.793503"
254 height="24.507414"
255 x="354.93326"
256 y="319.3302" />
257 <rect
258 style="fill:none;stroke:#0f0707;stroke-width:1;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
259 id="rect4462-56"
260 width="46.68111"
261 height="14.80503"
262 x="371.12372"
263 y="416.56683" />
264 <path
265 style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:4, 4;stroke-dashoffset:0;marker-end:url(#Arrow1Mend)"
266 d="m 168.16199,427.96933 200.75202,-0.0631"
267 id="path4498"
268 inkscape:connector-curvature="0"
269 sodipodi:nodetypes="cc" />
270 <text
271 xml:space="preserve"
272 style="font-size:10px;font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Serif;-inkscape-font-specification:Sans Italic"
273 x="265.58035"
274 y="424.79111"
275 id="text4720"
276 sodipodi:linespacing="125%"><tspan
277 sodipodi:role="line"
278 id="tspan4722"
279 x="265.58035"
280 y="424.79111"
281 style="font-style:italic">starts</tspan></text>
282 <path
283 style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#Arrow1Mstart);marker-end:url(#Arrow1Mend)"
284 d="M 120.05231,424.68362 C 83.811222,414.77578 84.686394,352.17218 101.2907,331.92244"
285 id="path4728"
286 inkscape:connector-curvature="0"
287 sodipodi:nodetypes="cc" />
288 <text
289 xml:space="preserve"
290 style="font-size:10px;font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Serif;-inkscape-font-specification:Sans Italic"
291 x="80.388351"
292 y="381.25613"
293 id="text4912"
294 sodipodi:linespacing="125%"><tspan
295 sodipodi:role="line"
296 id="tspan4914"
297 x="80.388351"
298 y="381.25613"
299 style="font-style:normal">6,8</tspan></text>
300 <path
301 style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow1Mend)"
302 d="m 394.64287,343.09357 -1e-5,71.06255"
303 id="path5100"
304 inkscape:connector-curvature="0"
305 sodipodi:nodetypes="cc" />
306 <text
307 xml:space="preserve"
308 style="font-size:10px;font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Serif;-inkscape-font-specification:Sans Italic"
309 x="396.73215"
310 y="375.54449"
311 id="text5284"
312 sodipodi:linespacing="125%"><tspan
313 sodipodi:role="line"
314 id="tspan5286"
315 x="396.73215"
316 y="375.54449"
317 style="font-style:normal">10</tspan></text>
318 <text
319 xml:space="preserve"
320 style="font-size:10px;font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Serif;-inkscape-font-specification:Sans Italic"
321 x="266.08542"
322 y="327.98129"
323 id="text5288"
324 sodipodi:linespacing="125%"><tspan
325 sodipodi:role="line"
326 id="tspan5290"
327 x="266.08542"
328 y="327.98129"
329 style="font-style:normal">3</tspan></text>
330 <rect
331 style="fill:none;stroke:#0f0707;stroke-width:1;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
332 id="rect6256"
333 width="141.78572"
334 height="189.64285"
335 x="68.928574"
336 y="268.93362" />
337 <rect
338 style="fill:none;stroke:#0f0707;stroke-width:1;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
339 id="rect6256-1"
340 width="141.78572"
341 height="189.64285"
342 x="323.75"
343 y="268.43362" />
344 <text
345 xml:space="preserve"
346 style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Serif;-inkscape-font-specification:Serif"
347 x="442.91574"
348 y="452.79074"
349 id="text4430-9"
350 sodipodi:linespacing="125%"><tspan
351 sodipodi:role="line"
352 id="tspan4432-9"
353 x="442.91574"
354 y="452.79074"
355 style="font-style:normal;-inkscape-font-specification:Serif">Host n</tspan></text>
356 <g
357 id="g3068"
358 transform="translate(-0.35714,32.785706)">
359 <text
360 sodipodi:linespacing="125%"
361 id="text3053"
362 y="189.99107"
363 x="265.58035"
364 style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Serif;-inkscape-font-specification:Sans"
365 xml:space="preserve"><tspan
366 y="189.99107"
367 x="265.58035"
368 id="tspan3055"
369 sodipodi:role="line">Execution wrapper</tspan></text>
370 <rect
371 y="178.5625"
372 x="210.58035"
373 height="16.785715"
374 width="110.71429"
375 id="rect3057"
376 style="fill:none;stroke:#0f0707;stroke-width:1;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" />
377 </g>
378 <g
379 id="g3063"
380 transform="translate(2.5000072,35.642857)">
381 <text
382 sodipodi:linespacing="125%"
383 id="text3049"
384 y="145.77679"
385 x="262.72321"
386 style="font-size:10px;font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Serif;-inkscape-font-specification:Sans Italic"
387 xml:space="preserve"><tspan
388 style="font-style:normal;-inkscape-font-specification:Serif"
389 y="145.77679"
390 x="262.72321"
391 id="tspan3051"
392 sodipodi:role="line">Scheduler</tspan></text>
393 <rect
394 y="133.99107"
395 x="233.08035"
396 height="16.428572"
397 width="60"
398 id="rect3059"
399 style="fill:none;stroke:#0f0707;stroke-width:1;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" />
400 </g>
401 <path
402 style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow1Mend)"
403 d="m 265.58036,186.0625 0,23.46429"
404 id="path3073"
405 inkscape:connector-curvature="0" />
406 <text
407 xml:space="preserve"
408 style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Serif;-inkscape-font-specification:Sans"
409 x="188.65617"
410 y="253.72234"
411 id="text4235"
412 sodipodi:linespacing="125%"><tspan
413 sodipodi:role="line"
414 id="tspan4237"
415 x="188.65617"
416 y="253.72234"
417 style="font-style:normal">2</tspan></text>
418 <text
419 xml:space="preserve"
420 style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Serif;-inkscape-font-specification:Sans"
421 x="348.52972"
422 y="252.59338"
423 id="text4235-4"
424 sodipodi:linespacing="125%"><tspan
425 sodipodi:role="line"
426 id="tspan4237-7"
427 x="348.52972"
428 y="252.59338"
429 style="font-style:normal">2</tspan></text>
430 <path
431 style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow1Mend)"
432 d="M 157.77049,-39.228872 C 121.40108,-10.95579 100.0674,7.9654718 75.267857,48.178572"
433 id="path4260"
434 inkscape:connector-curvature="0"
435 transform="translate(68.4375,267.9375)"
436 sodipodi:nodetypes="cc" />
437 <path
438 style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow1Mend)"
439 d="m 232.5,-39.228872 c 50.84902,29.8081673 81.39715,52.309479 106.9979,88.878673"
440 id="path4448"
441 inkscape:connector-curvature="0"
442 transform="translate(68.4375,267.9375)"
443 sodipodi:nodetypes="cc" />
444 <text
445 xml:space="preserve"
446 style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Serif;-inkscape-font-specification:Sans"
447 x="272.48795"
448 y="200.4348"
449 id="text4636"
450 sodipodi:linespacing="125%"><tspan
451 sodipodi:role="line"
452 id="tspan4638"
453 x="272.48795"
454 y="200.4348"
455 style="font-style:normal">1</tspan></text>
456 <path
457 style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#Arrow1Mstart);marker-end:url(#Arrow1Mend)"
458 d="m 353.03439,332.25537 c -18.36215,-0.16369 -133.52214,0.0345 -159.0412,0.60971"
459 id="path4039"
460 inkscape:connector-curvature="0"
461 sodipodi:nodetypes="cc" />
462 <text
463 xml:space="preserve"
464 style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Serif;-inkscape-font-specification:Sans"
465 x="269.71039"
466 y="350.38989"
467 id="text4231"
468 sodipodi:linespacing="125%"><tspan
469 sodipodi:role="line"
470 id="tspan4233"
471 x="269.71039"
472 y="350.38989" /></text>
473 <text
474 xml:space="preserve"
475 style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Serif;-inkscape-font-specification:Sans"
476 x="266.65179"
477 y="345.34824"
478 id="text4272"
479 sodipodi:linespacing="125%"><tspan
480 sodipodi:role="line"
481 id="tspan4274"
482 x="266.65179"
483 y="345.34824">MPI</tspan></text>
484 <text
485 xml:space="preserve"
486 style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Serif;-inkscape-font-specification:Serif"
487 x="358.54596"
488 y="334.14789"
489 id="text2985-5"
490 sodipodi:linespacing="125%"><tspan
491 sodipodi:role="line"
492 x="358.54596"
493 y="334.14789"
494 id="tspan4262-0"
495 style="text-align:start;text-anchor:start">mshd (worker)</tspan></text>
496 <path
497 style="fill:none;stroke:none"
498 d="m 33.84011,163.65058 c -44.194174,26.26397 0.252538,90.66119 18.182746,87.88327"
499 id="path3063"
500 inkscape:connector-curvature="0"
501 transform="translate(68.4375,169.14286)" />
502 <path
503 style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker-start:url(#Arrow1Mstart);marker-end:url(#Arrow1Mend)"
504 d="M 100.51018,251.28131 285.36809,168.4488"
505 id="path4225"
506 inkscape:connector-curvature="0"
507 transform="translate(68.4375,169.14286)"
508 sodipodi:nodetypes="cc" />
509 <text
510 xml:space="preserve"
511 style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Serif;-inkscape-font-specification:Serif"
512 x="266.47687"
513 y="394.60437"
514 id="text5543"><tspan
515 sodipodi:role="line"
516 id="tspan5545"
517 x="268.06866"
518 y="394.60437">7, 9, 11 </tspan></text>
519 </g>
520</svg>
diff --git a/doc/msh.tex b/doc/msh.tex
new file mode 100644
index 0000000..9c728f1
--- /dev/null
+++ b/doc/msh.tex
@@ -0,0 +1,368 @@
1\documentclass[10pt, a4paper, onecolumn, oneside]{scrreprt}
2\usepackage[utf8]{inputenc}
3\usepackage{color}
4\usepackage{graphicx}
5\usepackage{import}
6\usepackage{amsfonts}
7\usepackage[pdftex,hyperfootnotes=false,pdfpagelabels]{hyperref}
8\usepackage{listings}
9\usepackage[sorting=none]{biblatex}
10%\usepackage{courier}
11
12\graphicspath{{fig/svg/}}
13\bibliography{related_work}
14
15
16\title{MSH: A remote shell based on MPI}
17\author{Sree Harsha Totakura}
18\lstset{language=bash,
19 basicstyle=\small\ttfamily,
20 numbers=left,
21 numberstyle=\tiny,
22 frame=b,
23 columns=fullflexible,
24 showstringspaces=false,
25 captionpos=b
26}
27
28\newcommand\todo[1]{
29 \marginpar{\textcolor{red}{TBD:} #1}
30 \PackageWarning{TODO:}{ #1}
31}
32
33\begin{document}
34\maketitle
35\cleardoublepage
36\tableofcontents
37\cleardoublepage
38\listoffigures
39\cleardoublepage
40\begin{abstract}
41 MPI-Shell (MSH) is a remote shell for executing commands remotely on hosts
42 where Message Passing Interface (MPI) layer is available for communication.
43 Such hosts are commonly found in High Performance Computing (HPC) systems such
44 as compute clusters or supercomputers.
45
46 The motivation for this project is that often in such systems Secure-Shell
47 (SSH) is either unavailable or restricted for users due to security reasons.
48 As a result, hosts in these systems cannot be used for non MPI applications
49 such as network emulators or testbeds which rely on SSH to establish
50 connections among the hosts. MSH aims to solve this problem by
51 providing an alternative remote shell which can be used by these applications
52 instead of SSH.
53\end{abstract}
54
55\cleardoublepage
56\chapter{Technical Documentation}
57
58\section{Introduction}
59Large scale network experimentation of distributed systems is achieved by
60distributing the experiment across multiple physical nodes~\cite{dpeersim, wids,
61 netlab, cset2011evans, totakura2013ms}. These tools coordinate the experiment
62among the hosts by establishing SSH connections to run remote commands on the
63available hosts.
64
65A limiting factor in scaling network experiments in the availability of
66computing power and underlying network. This requirement for resources can be
67addressed by running network experiments on High Performance Computing (HPC)
68systems which are made up of many hosts interconnected with a high speed and
69high bandwidth network.
70
71The usage of HPC systems poses some new challenges: since HPC systems are used
72by multiple users simultaneously, they allocate exclusive resources dynamically.
73The user has to determine these dynamically allocated resources before starting
74the experiment on these resources. The \textit{de-facto} standard for remote
75command execution, SSH, is increasingly made unavailable or restricted on HPC
76systems~\cite{supermuc} to prevent users from accessing resources which are not
77allocated to them. While such restriction does not effect the intended usage of
78HPC systems which is to run parallel programs with Message Passing Interface
79(MPI) for communications, it presents users to use network experimentation tools
80which rely on remote command execution.
81
82To overcome these challenges we propose, MSH, a new remote command execution
83system which uses MPI for determining node allocation and addressing. Our aims
84are: to provide MSH as a substitute for SSH for remote command execution; to
85make MSH behave similar to SSH such that the network experimentation tools do
86not have to be heavily modified; to determine the dynamically allocated
87resources on the HPC system and, finally, to be able to run network experiments
88on HPC systems.
89
90\section{Architecture}
91
92MSH consists of two components: the \texttt{mshd} daemon and the \texttt{msh}
93client. \texttt{mshd} is similar to \texttt{sshd} in that one \texttt{mshd}
94daemon per host is started. The daemons execute the commands given from remote
95\texttt{msh} clients. However, unlike \texttt{sshd}, \texttt{mshd} is started
96by the job scheduler and only runs during the job.
97
98The MSH client, \texttt{msh}, takes the IP address of the target host and the
99remote command string as arguments. The client relies on the local
100\texttt{mshd} for learning the address of the remote \texttt{mshd} and
101authenticating itself to the remote \texttt{mshd}.
102
103The command string is executed by the remote \texttt{mshd} after successful
104authentication of \texttt{msh}. The input for the executed command string is
105relayed by \texttt{msh} to the remote \texttt{mshd}. Similarly, the output from
106the executed command string is relayed from the remote \texttt{mshd} to
107\texttt{msh};
108
109\begin{figure}[ht]
110 \centering
111 \input{fig/svg/job_startup.pdf_tex}
112 \caption[Job start-up overview]{Job start-up overview }
113 \label{fig:job_startup}
114\end{figure}
115
116An overview of the interactions involved in starting an application with MSH is
117shown in Figure~\ref{fig:job_startup}:
118\begin{enumerate}
119\item The job scheduler starts the execution wrapper which is used to start
120 multiple instances of MPI programs. Examples for execution wrappers are
121 \texttt{mpiexec}, \texttt{mpirun}, \texttt{poe} and \texttt{srun}.
122\item The execution wrapper starts an \texttt{mshd} instance on each of the
123 allocated hosts. We distinguish the instance having MPI ID 0 as the master
124 instance and all other instances as worker instances.
125\item The instances resolve their addresses. This is further detailed in
126 Section~\ref{sec:addressing}.
127\item All the \texttt{mshd} instances open a local socket for IPC and set the
128 environmental variable \texttt{MSHD\_SOCK} to refer to this socket. They also
129 write to a file the addresses of hosts they learn in step 3. The name of this
130 file is made available through environmental variable
131 \texttt{MP\_SAVEHOSTFILE}. The master instance then starts the given
132 application given as an argument to \texttt{mshd} in the execution wrapper.
133\item The application knows about the available hosts through the environmental
134 variable \texttt{MP\_SAVEHOSTFILE} and calls \texttt{msh} for executing a
135 remote commands on those hosts.
136\item The \texttt{msh} program inherits the environmental variables
137 \texttt{MSHD\_SOCK} set by the master instance and uses it for establishing
138 IPC with the master instance. Using this IPC it learns from the local
139 \texttt{mshd} instance the address of the remote \texttt{mshd} running on the
140 given host.
141\item \texttt{msh} establishes connection to the remote \texttt{mshd} on the
142 learned address and delivers the remote command string that is to be
143 executed. The remote \texttt{mshd} responds with an authentication challenge.
144\item \texttt{msh} forwards the authentication challenge to its local
145 \texttt{mshd} through the IPC it established from step 6. The local
146 \texttt{mshd} responds with a challenge-response.
147\item The challenge-response is forwarded to the remote \texttt{mshd}.
148\item The remote \texttt{mshd} verifies the challenge-response and it
149 successfully verified, it starts executes the command string
150\item The input and output streams for the remote command string are relayed
151 from \texttt{msh} and \texttt{mshd} to each other respectively. Unlike SSH,
152 the streams are not encrypted as we only use MSH on HPC systems.
153\end{enumerate}
154
155\section{Resource Discovery and Addressing}
156\label{sec:addressing}
157
158One of our aims is to determine the resources which are dynamically allocated to
159us and provide their details to the experimentation tools. Since we intend to
160use MSH as a substitute for SSH, we provide the resources' IP addresses so that
161the tools can refer to these resources by IP addresses.
162
163The mapping between the allocated hosts and their IP addresses is determined by
164having each \texttt{mshd} instance verify the IP addresses of all other
165\texttt{mshd} instances running on the allocated hosts. The verification
166proceeds in rounds where each instance verifies IP addresses of several
167instances. At the beginning of each round, every instance opens a socket bound
168to a random port and all available IP addresses on its host and sends the IP
169addresses to a set of instances $\mathbb{N}$ for verification. The set
170$\mathbb{N}$ is determined from the set of all instances $\mathbb{I}$
171depending on the current round $r$ and the round width $R$ as follows:
172\begin{center}
173 $ \mathbb{N} = \{i\in \mathbb{I} | (rR + 1) \le i \le (rR + r)\} $
174\end{center}
175The instances verify the IP addresses of the sending instance by establishing
176TCP connections to the sender's listening socket with one TCP connection for
177each of the sender's IP addresses. The TCP connections are started in parallel
178and in non-blocking mode. This is depicted in Figure~\ref{fig:ip_map}.
179
180\begin{figure}[ht]
181 \centering
182 \input{fig/svg/ip_map.pdf_tex}
183 \caption{Instances verifying IP addresses during $i^{th}$ round}
184 \label{fig:ip_map}
185\end{figure}
186
187At the end of the last round, all instances would have verified the IP
188addresses of other instances and posses an instance-to-IP mapping. At this point,
189they accumulate their mappings using a reduction algorithm (binary/ binomial
190tree reduction). The reduction is made by intersecting the reported IP
191addresses for an instance.
192
193\section{Limitations}
194MSH does not have terminal handling capabilities yet. This means that
195applications such as \texttt{screen}, \texttt{less}, \texttt{vim} which require
196terminal (\texttt{tty}) support do not work through MSH. This also means that
197there is no support for sending control character sequences such as
198\texttt{Control+C} to the remote command.
199
200\cleardoublepage
201\chapter{User Guide}
202This chapter provides information for the installation of MSH and its usage. We
203provide examples which showcase how MSH is used in experiments conducted on HPC
204systems.
205
206\section{Installation}
207The source code for MSH is available from our Subversion repository:\\
208\url{https://gnunet.org/svn/msh/}.
209
210MSH depends on GNUnet's networking API and hence requires
211GNUnet\footnote{\url{https://gnunet.org/}} to be installed. GNUnet sources can
212be downloaded from its repository at \url{https://gnunet.org/svn/gnunet/}.
213Additionally, it requires an MPI implementation to be installed together with
214the MPI compiler wrapper \texttt{mpicc}. Note that the repositories for MSH and
215GNUnet are used for active development and hence checking out the current
216versions may sometimes break the stability of MSH or simply may not compile.
217The version we tested to be stable at the time of writing this document is
218\texttt{30205}. The corresponding version for GNUnet is also \texttt{30205}.
219
220Once the dependencies are installed, MSH can be installed by running the
221commands listed in Listing~\ref{lst:installation} in the MSH source directory:
222\begin{lstlisting}[language=bash,caption=Installation commands,label=lst:installation]
223$ ./configure
224$ make
225$ make install
226\end{lstlisting} %$
227
228If the required dependencies are not in the default search paths of the
229compiler, \texttt{configure} may fail complaining an error. These can be fixed
230by providing the installation directories of the dependencies to
231\texttt{configure}. For a list of available options type:
232\texttt{./configure -{}-help}
233
234
235\section{Starting MSH}
236MSH is started by running the MSH daemon on the available nodes through the MPI
237execution wrappers. The available nodes are determined either manually and
238given to the execution wrapper as a hostlist file (as in the case with small
239group of systems or clusters) or dynamically by either a job scheduling system
240such as LoadLeveler\cite{prenneis1996loadleveler} or SLURM\cite{yoo2003slurm}.
241The execution wrappers can be started as an interactive job or as a batch job.
242Interactive job execution gives more control to the user as the user can
243directly interact with the job through the job's standard input and output.
244Batch job execution allows for the job to be queued in a batch scheduling system
245which executes the job whenever the required number of resources are available.
246
247Since only one MSH daemon should run on each host, the wrappers are configured
248with the respective parameters such that they start only one instance of MSH per
249host.
250
251Examples for starting MSH on various HPC systems are shown in the following
252listings. \todo{Need more examples}
253
254\begin{lstlisting}[language=bash, caption=Starting MSH as an interactive job on
255 a cluster with SLURM job manager, label=lst:slurm_interactive, numbers=left]
256$ salloc --ntasks-per-node=1 -N 3 -p mpp1_inter
257$ srun_ps mshd -- /bin/bash
258\end{lstlisting}
259
260Listing~\ref{lst:slurm_interactive} shows interactive MSH startup on an MPI
261cluster. The cluster uses SLURM for job scheduling. The command
262\texttt{salloc} in line 1 is used to allocate resources. Here we allocate 3
263nodes from the cluster partition \texttt{mpp1\_inter} and configure the MPI
264execution wrapper to run 1 MPI process per node. When the allocation is
265successful, \texttt{mshd} is launched in line 2 with the command
266\texttt{srun\_ps} which is specific to SLURM for launching MPI programs. When
267MSH is launched successfully, the root \texttt{mshd} process will start
268\texttt{bash}.
269
270\begin{lstlisting}[language=bash, caption=Starting MSH as an interactive job using
271 LoadLeveler, label=lst:ll_interactive, numbers=left]
272$ export MP_NODES=3
273$ export MP_TASKS_PER_NODE=1
274$ poe mshd -- /bin/bash
275\end{lstlisting} %$
276
277Listing~\ref{lst:ll_interactive} shows interactive MSH startup on SuperMUC using
278the LoadLeveler scheduler. In lines 1, 2 we specify that we want to allocate 3
279nodes for our experiment and only one instance of \texttt{mshd} has to be
280started on each of them. In line 3, we start \texttt{mshd} processes through
281the LoadLeveler's \texttt{poe} command.
282
283\section{Using MSH}
284\label{sec:using}
285
286The usage of MSH is aimed at HPC systems where remote shells are disabled and
287MPI is available. With MSH, we address two problems: 1. we facilitate remote
288command execution and 2. we provide an easy interface to learn which hosts are
289allocated to the job by listing their addresses.
290
291The IP addresses of the hosts are made available as hostlist file to the
292processes \texttt{mshd} processes start. The path of this hostlist file is made
293available through the environmental variable \texttt{MP\_SAVEHOSTFILE}.
294\texttt{msh} can be used to connect to any of the hosts listed in this file.
295Listing~\ref{lst:msh_connect} shows an example for connecting to the allocated
296hosts. The commands are executed in a \texttt{bash} process started by the root
297\texttt{mshd} instance (run from the line 2 in Listing~\ref{lst:slurm_interactive}).
298
299\begin{lstlisting}[language=bash, caption=Using \texttt{msh} to connect to
300 remote hosts. The commands are run in a \texttt{bash} process started through
301 MSH in a cluster, label=lst:msh_connect]
302$ cat $MP_SAVEHOSTFILE
30310.0.0.3
30410.0.0.4
30510.0.0.5
306$ msh 10.0.0.4 date
307Fri Sep 6 11:17:09 CEST 2013
308$ quit
309\end{lstlisting}
310
311MSH can also be used by programs which are started by \texttt{mshd} instances.
312The programs however should take care to read the addresses of allocated hosts
313from the hostlist file from the evironmental variable and use \texttt{msh} for
314executing remote commands on those hosts.
315
316In our experiments, our distributed testbed~\cite{totakura2013ms} determines the
317allocated hosts through the hostfile and uses \texttt{msh} to spawn controllers
318for each allocated host. The start-up of the testbed is initiated from the root
319\texttt{mshd} instance which starts a master controller on the host where the
320root \texttt{mshd} instance is running.
321Listing~\ref{slurm_interactive_testbed_startup} shows the commands used to start
322the testbed. In the same way, other simulation and emulation software for
323network experiments which rely on SSH for starting remote processes can use MSH
324as a replacement for SSH.
325
326\begin{lstlisting}[language=bash, label=slurm_interactive_testbed_startup,
327 caption=Commands to start a testbed program which uses MSH]
328$ salloc --ntasks-per-node=1 -N 3 -p mpp1_inter
329$ srun_ps mshd -- ./gnunet-testbed-profiler \
330 -c ../../contrib/testbed_infiniband.conf -p 1000 -e 5
331\end{lstlisting}
332
333On a system with LoadLeveler such as SuperMUC the above experiment startup is
334shown in Listing~\ref{lst:ll_interactive_testbed_startup}
335
336\begin{lstlisting}[language=bash, label=lst:ll_interactive_testbed_startup,
337 caption=Commands to start testbed program which uses MSH with LoadLeveler
338 scheduler]
339$ export MP_NODES=3
340$ export MP_TASKS_PER_NODE=1
341$ poe mshd -- ./gnunet-testbed-profiler \
342 -c ../../contrib/testbed_infiniband.conf -p 1000 -e 5
343\end{lstlisting} %$
344
345\section{Termination}
346\label{sec:termination}
347
348Termination in MSH can be divided into two parts: the termination of remote
349access connections started through \texttt{msh} processes and the termination of
350\texttt{mshd} processes.
351
352\texttt{msh} processes terminate successfully when the remote command execution
353is complete and all the output from the command is fetched from the remote
354host. They terminate with error if the remote connection is broken, remote
355\texttt{mshd} process crashes or remote host goes down, if the given command is
356not found on the remote host and if the local \texttt{msh} processes receives
357any of the termination (SIGTERM, SIGINT) signals.
358
359The \texttt{mshd} processes terminate successfully when the main process started
360by the root \texttt{mshd} processes terminates. They terminate with error if
361the main process crashes or terminates with error, or if the binary needed for
362launching the main process is not found, or upon a crash of any of the
363\texttt{mshd} processes.
364
365\cleardoublepage
366\printbibliography
367
368\end{document}
diff --git a/doc/related_work.bib b/doc/related_work.bib
new file mode 100644
index 0000000..e6066d0
--- /dev/null
+++ b/doc/related_work.bib
@@ -0,0 +1,1466 @@
1@mastersthesis {totakura2013ms,
2 title = {Large Scale Distributed Evaluation of Peer-to-Peer Protocols},
3 volume = {Master of Science},
4 year = {2013},
5 month = {6},
6 pages = {76},
7 school = {Technische Universit\"at M\"unchen},
8 type = {Masters },
9 address = {Garching bei M\"unchen},
10 abstract = {Evaluations of P2P protocols during the system{\textquoteright}s design and implementation phases are commonly done through simulation and emulation respectively. While the current state-of-the-art simulation allows evaluations with many millions of peers through the use of abstractions, emulation still lags behind as it involves executing the real implementation at some parts of the system. This difference in scales can make it hard to relate the evaluations made created with simulation and emulation during the design and implementation phases and can results in a limited evaluation of the implementation, which may cause severe problems after deployment.
11
12In this thesis, we build upon an existing emulator for P2P applications to push the scales offered by emulation towards the limits set by simulation. Our approach distributes and co-ordinates the emulation across many hosts. Large deployments are possible by deploying hundreds or thousands of peers on each host.
13
14To address the varying needs of an experimenter and the range of available hardware, we make our approach scalable such that it can easily be adapted to run evaluations on a single machine or a large group of hosts. Specifically, the system automatically adjusts the number of overlapping operations to the available resources efficiently using a feedback mechanism, thus relieving the experimenter from the hassles of manual tuning.
15
16We specifically target HPC systems like compute clusters and supercomputers and demonstrate how such systems can be used for large scale emulations by evaluating two P2P applications with deployment sizes up to 90k peers on a supercomputer.},
17 keywords = {emulation, GNUnet, large scale testing, protocol evaluation, testbed},
18 author = {Totakura, Sree Harsha}
19}
20
21@INPROCEEDINGS{yoo2003slurm,
22 title={SLURM: Simple linux utility for resource management},
23 author={Yoo, Andy B and Jette, Morris A and Grondona, Mark},
24 booktitle={Job Scheduling Strategies for Parallel Processing},
25 pages={44--60},
26 year={2003},
27 organization={Springer}
28}
29
30@ARTICLE{prenneis1996loadleveler,
31 title={Loadleveler: Workload management for parallel and distributed computing environments},
32 author={Prenneis Jr, A},
33 journal={Proceedings of Supercomputing Europe (SUPEUR)},
34 volume={176},
35 year={1996}
36}
37
38
39
40@INPROCEEDINGS{DBLP:conf/tridentcom/AlbrechtH10,
41 author = {Jeannie R. Albrecht and Danny Yuxing Huang},
42 title = {Managing Distributed Applications Using Gush},
43 booktitle = {TRIDENTCOM},
44 year = {2010},
45 pages = {401-411},
46 bibsource = {DBLP, http://dblp.uni-trier.de},
47 crossref = {DBLP:conf/tridentcom/2010},
48 ee = {http://dx.doi.org/10.1007/978-3-642-17851-1_31},
49 file = {:gush.pdf:PDF}
50}
51
52@INPROCEEDINGS{DBLP:conf/acsac/EvansGG07,
53 author = {Nathan S. Evans and Chris GauthierDickey and Christian Grothoff},
54 title = {Routing in the Dark: Pitch Black},
55 booktitle = {ACSAC},
56 year = {2007},
57 pages = {305-314},
58 bibsource = {DBLP, http://dblp.uni-trier.de},
59 crossref = {DBLP:conf/acsac/2007},
60 ee = {http://doi.ieeecomputersociety.org/10.1109/ACSAC.2007.36},
61 file = {:RoutingintheDark.pdf:PDF}
62}
63
64@INPROCEEDINGS{DBLP:conf/tridentcom/HermenierR12,
65 author = {Fabien Hermenier and Robert Ricci},
66 title = {How to Build a Better Testbed: Lessons from a Decade of Network Experiments
67 on Emulab},
68 booktitle = {TRIDENTCOM},
69 year = {2012},
70 pages = {287-304},
71 bibsource = {DBLP, http://dblp.uni-trier.de},
72 crossref = {DBLP:conf/tridentcom/2012},
73 ee = {http://dx.doi.org/10.1007/978-3-642-35576-9_24},
74 file = {:how-to-build-a-better-testbed.pdf:PDF}
75}
76
77@INPROCEEDINGS{emulab,
78 author = {Mike Hibler and Robert Ricci and Leigh Stoller and Jonathon Duerig
79 and Shashi Guruprasad and Tim Stack and Kirk Webb and Jay Lepreau},
80 title = {Large-scale Virtualization in the Emulab Network Testbed},
81 booktitle = {USENIX Annual Technical Conference},
82 year = {2008},
83 pages = {113-128},
84 bibsource = {DBLP, http://dblp.uni-trier.de},
85 crossref = {DBLP:conf/usenix/2008},
86 ee = {http://www.usenix.org/events/usenix08/tech/fullpapers/hibler/hibler.pdf},
87 file = {:emulab_virtualisation.pdf:PDF}
88}
89
90@INPROCEEDINGS{DBLP:conf/tridentcom/NguyenRKFMB10,
91 author = {Hung X. Nguyen and Matthew Roughan and Simon Knight and Nick Falkner
92 and Olaf Maennel and Randy Bush},
93 title = {How to Build Complex, Large-Scale Emulated Networks},
94 booktitle = {TRIDENTCOM},
95 year = {2010},
96 pages = {3-18},
97 bibsource = {DBLP, http://dblp.uni-trier.de},
98 crossref = {DBLP:conf/tridentcom/2010},
99 ee = {http://dx.doi.org/10.1007/978-3-642-17851-1_1},
100 file = {:AutoNetkit.pdf:PDF}
101}
102
103@INPROCEEDINGS{DBLP:conf/tridentcom/PeralaPML10,
104 author = {Pekka H. J. Per{\"a}l{\"a} and Jori P. Paananen and Milton Mukhopadhyay
105 and Jukka-Pekka Laulajainen},
106 title = {A Novel Testbed for P2P Networks},
107 booktitle = {TRIDENTCOM},
108 year = {2010},
109 pages = {69-83},
110 bibsource = {DBLP, http://dblp.uni-trier.de},
111 crossref = {DBLP:conf/tridentcom/2010},
112 ee = {http://dx.doi.org/10.1007/978-3-642-17851-1_5},
113 file = {:A Novel Testbed for P2P Networks.pdf:PDF}
114}
115
116@ARTICLE{albrecht2006planetlab,
117 author = {Albrecht, J. and Tuttle, C. and Snoeren, A.C. and Vahdat, A.},
118 title = {PlanetLab application management using Plush},
119 journal = {ACM SIGOPS Operating Systems Review},
120 year = {2006},
121 volume = {40},
122 pages = {33--40},
123 number = {1},
124 file = {:plush.pdf:PDF},
125 publisher = {ACM}
126}
127
128@BOOK{infiniband2000,
129 title = {InfiniBand Architecture Specification: Release 1.0},
130 publisher = {InfiniBand Trade Association},
131 year = {2000},
132 author = {InfiniBand Trade Association}
133}
134
135@BOOK{banks1998handbook,
136 title = {Handbook of simulation},
137 publisher = {Wiley Online Library},
138 year = {1998},
139 author = {Banks, Jerry and others}
140}
141
142@ARTICLE{barabasi1999emergence,
143 author = {Barab{\'a}si, Albert-L{\'a}szl{\'o} and Albert, R{\'e}ka},
144 title = {Emergence of scaling in random networks},
145 journal = {science},
146 year = {1999},
147 volume = {286},
148 pages = {509--512},
149 number = {5439},
150 file = {:emergence_of_scaling_in_random_networks.pdf:PDF},
151 publisher = {American Association for the Advancement of Science}
152}
153
154@ARTICLE{barham2003xen,
155 author = {Barham, Paul and Dragovic, Boris and Fraser, Keir and Hand, Steven
156 and Harris, Tim and Ho, Alex and Neugebauer, Rolf and Pratt, Ian
157 and Warfield, Andrew},
158 title = {Xen and the art of virtualization},
159 journal = {ACM SIGOPS Operating Systems Review},
160 year = {2003},
161 volume = {37},
162 pages = {164--177},
163 number = {5},
164 publisher = {ACM}
165}
166
167@INPROCEEDINGS{oversim,
168 author = {Baumgart, I. and Heep, B. and Krause, S.},
169 title = {OverSim: A Flexible Overlay Network Simulation Framework},
170 booktitle = {IEEE Global Internet Symposium, 2007},
171 year = {2007},
172 pages = {79-84},
173 doi = {10.1109/GI.2007.4301435},
174 file = {:OverSim_2007.pdf:PDF},
175 keywords = {graphical user interfaces;peer-to-peer computing;protocols;OMNeT++;OverSim;flexible
176 overlay network simulation framework;generic lookup mechanism;overlay
177 protocols;peer-to- peer networks;peer-to-peer protocols;Access protocols;Application
178 software;Computational modeling;Costs;Discrete event simulation;Java;Next
179 generation networking;Object oriented modeling;Peer to peer computing;Testing}
180}
181
182@INPROCEEDINGS{deter,
183 author = {Benzel, T. and Braden, R. and Kim, D. and Neuman, C. and Joseph,
184 A. and Sklower, K. and Ostrenga, R. and Schwab, S.},
185 title = {Experience with DETER: a testbed for security research},
186 booktitle = {Testbeds and Research Infrastructures for the Development of Networks
187 and Communities, 2006. TRIDENTCOM 2006. 2nd International Conference
188 on},
189 year = {2006},
190 pages = {10 pp.-388},
191 doi = {10.1109/TRIDNT.2006.1649172},
192 issn = {Not Applica},
193 keywords = {security of data;telecommunication security;DETER;malicious code;security
194 research;Computer science;Computer security;Data security;Hardware;Information
195 security;Internet;Protection;System testing;Telecommunication traffic;Traffic
196 control}
197}
198
199@ARTICLE{grid5000,
200 author = {Bolze, Raphaël and Cappello, Franck and Caron, Eddy and Daydé, Michel
201 and Desprez, Frédéric and Jeannot, Emmanuel and Jégou, Yvon and Lanteri,
202 Stephane and Leduc, Julien and Melab, Noredine and Mornet, Guillaume
203 and Namyst, Raymond and Primet, Pascale and Quetier, Benjamin and
204 Richard, Olivier and Talbi, El-Ghazali and Touche, Iréa},
205 title = {Grid'5000: A Large Scale And Highly Reconfigurable Experimental Grid
206 Testbed},
207 journal = {International Journal of High Performance Computing Applications},
208 year = {2006},
209 volume = {20},
210 pages = {481-494},
211 number = {4},
212 abstract = {Large scale distributed systems such as Grids are difficult to study
213 from theoretical models and simulators only. Most Grids deployed
214 at large scale are production platforms that are inappropriate research
215 tools because of their limited reconfiguration, control and monitoring
216 capabilities. In this paper, we present Grid'5000, a 5000 CPU nation-wide
217 infrastructure for research in Grid computing. Grid'5000 is designed
218 to provide a scientific tool for computer scientists similar to the
219 large-scale instruments used by physicists, astronomers, and biologists.
220 We describe the motivations, design considerations, architecture,
221 control, and monitoring infrastructure of this experimental platform.
222 We present configuration examples and performance results for the
223 reconfiguration subsystem.},
224 doi = {10.1177/1094342006070078},
225 eprint = {http://hpc.sagepub.com/content/20/4/481.full.pdf+html},
226 url = {http://hpc.sagepub.com/content/20/4/481.abstract}
227}
228
229@ARTICLE{2009Chertov,
230 author = {Chertov, Roman and Fahmy, Sonia and Shroff, Ness B.},
231 title = {Fidelity of network simulation and emulation: A case study of TCP-targeted
232 denial of service attacks},
233 journal = {ACM Trans. Model. Comput. Simul.},
234 year = {2009},
235 volume = {19},
236 pages = {4:1--4:29},
237 number = {1},
238 month = jan,
239 acmid = {1456649},
240 address = {New York, NY, USA},
241 articleno = {4},
242 doi = {10.1145/1456645.1456649},
243 file = {:fidelity_sim_emu.pdf:PDF},
244 issn = {1049-3301},
245 issue_date = {December 2008},
246 keywords = {Simulation, TCP, congestion control, denial of service attacks, emulation,
247 low-rate TCP-targeted attacks, testbeds},
248 numpages = {29},
249 publisher = {ACM},
250 url = {http://doi.acm.org/10.1145/1456645.1456649}
251}
252
253@ARTICLE{planetlab,
254 author = {Chun, Brent and Culler, David and Roscoe, Timothy and Bavier, Andy
255 and Peterson, Larry and Wawrzoniak, Mike and Bowman, Mic},
256 title = {PlanetLab: an overlay testbed for broad-coverage services},
257 journal = {SIGCOMM Comput. Commun. Rev.},
258 year = {2003},
259 volume = {33},
260 pages = {3--12},
261 number = {3},
262 month = jul,
263 acmid = {956995},
264 address = {New York, NY, USA},
265 doi = {10.1145/956993.956995},
266 issn = {0146-4833},
267 issue_date = {July 2003},
268 numpages = {10},
269 publisher = {ACM},
270 url = {http://doi.acm.org/10.1145/956993.956995}
271}
272
273@INCOLLECTION{freenet,
274 author = {Clarke, Ian and Sandberg, Oskar and Wiley, Brandon and Hong, TheodoreW.},
275 title = {Freenet: A Distributed Anonymous Information Storage and Retrieval
276 System},
277 booktitle = {Designing Privacy Enhancing Technologies},
278 publisher = {Springer Berlin Heidelberg},
279 year = {2001},
280 editor = {Federrath, Hannes},
281 volume = {2009},
282 series = {Lecture Notes in Computer Science},
283 pages = {46-66},
284 doi = {10.1007/3-540-44702-4_4},
285 file = {:freenet.pdf:PDF},
286 isbn = {978-3-540-41724-8},
287 language = {English},
288 url = {http://dx.doi.org/10.1007/3-540-44702-4_4}
289}
290
291@MISC{cohen2008bittorrent,
292 author = {Cohen, Bram},
293 title = {The BitTorrent protocol specification},
294 year = {2008},
295 publisher = {BITTORRENT}
296}
297
298@ARTICLE{openmp,
299 author = {Dagum, L. and Menon, R.},
300 title = {OpenMP: an industry standard API for shared-memory programming},
301 journal = {Computational Science Engineering, IEEE},
302 year = {1998},
303 volume = {5},
304 pages = {46-55},
305 number = {1},
306 doi = {10.1109/99.660313},
307 issn = {1070-9924},
308 keywords = {application program interfaces;parallel programming;shared memory
309 systems;software portability;software reviews;software standards;Fortran;Fortran
310 90;Fortran 95;Fortran compiler;OpenMP;X3H5 concepts;allocatables;callable
311 runtime library;callable runtime library routines;coarse grain parallelism;compiler
312 directives;environment variables;industry standard API;pointers;shared
313 memory parallelism;shared memory programming;ANSI standards;Coherence;Computer
314 architecture;Hardware;Message passing;Parallel processing;Parallel
315 programming;Power system modeling;Scalability;Software systems}
316}
317
318@MISC{torproject,
319 author = {Dingledine, R and Mathewson, N and Syverson, P},
320 title = {TOR: the onion router. Tor Project/EFF},
321 howpublished = {\url{https://www.torproject.org/}}
322}
323
324@INPROCEEDINGS{dpeersim,
325 author = {Tien Tuan Anh Dinh and Lees, M. and Theodoropoulos, G. and Minson,
326 R.},
327 title = {Large Scale Distributed Simulation of p2p Networks},
328 booktitle = {Parallel, Distributed and Network-Based Processing, 2008. PDP 2008.
329 16th Euromicro Conference on},
330 year = {2008},
331 pages = {499-507},
332 doi = {10.1109/PDP.2008.67},
333 file = {:dpeersim.pdf:PDF},
334 keywords = {discrete event simulation;peer-to-peer computing;Chord p2p protocol;PeerSim;large
335 scale distributed simulation;p2p networks;parallel discrete event
336 simulation techniques;Algorithm design and analysis;Analytical models;Computational
337 modeling;Discrete event simulation;Large-scale systems;Network servers;Peer
338 to peer computing;Protocols;Robustness;Scalability;Distributed;Large
339 Scale;Parallel;Simulation}
340}
341
342@INPROCEEDINGS{Eger:2007:ESL:1272980.1272986,
343 author = {Eger, Kolja and Ho\ssfeld, Tobias and Binzenh\"{o}fer, Andreas and
344 Kunzmann, Gerald},
345 title = {Efficient simulation of large-scale p2p networks: packet-level vs.
346 flow-level simulations},
347 booktitle = {Proceedings of the second workshop on Use of P2P, GRID and agents
348 for the development of content networks},
349 year = {2007},
350 series = {UPGRADE '07},
351 pages = {9--16},
352 address = {New York, NY, USA},
353 publisher = {ACM},
354 acmid = {1272986},
355 doi = {10.1145/1272980.1272986},
356 file = {:p2p_sim_flow_level_vs_packet_level.pdf:PDF},
357 isbn = {978-1-59593-718-6},
358 keywords = {BitTorrent, content distribution, peer-to-peer, simulation},
359 location = {Monterey, California, USA},
360 numpages = {8},
361 url = {http://doi.acm.org/10.1145/1272980.1272986}
362}
363
364@ARTICLE{erdos,
365 author = {Erdos, Paul and R{\'e}nyi, Alfr{\'e}d},
366 title = {On the evolution of random graphs},
367 journal = {Bull. Inst. Internat. Statist},
368 year = {1961},
369 volume = {38},
370 pages = {343--347},
371 number = {4}
372}
373
374@ARTICLE{Eugster:2003:LPB:945506.945507,
375 author = {Eugster, P. Th. and Guerraoui, R. and Handurukande, S. B. and Kouznetsov,
376 P. and Kermarrec, A.-M.},
377 title = {Lightweight probabilistic broadcast},
378 journal = {ACM Trans. Comput. Syst.},
379 year = {2003},
380 volume = {21},
381 pages = {341--374},
382 number = {4},
383 month = nov,
384 acmid = {945507},
385 address = {New York, NY, USA},
386 doi = {10.1145/945506.945507},
387 issn = {0734-2071},
388 issue_date = {November 2003},
389 keywords = {Broadcast, buffering, garbage collection, gossip, noise, randomization,
390 reliability, scalability},
391 numpages = {34},
392 publisher = {ACM},
393 url = {http://doi.acm.org/10.1145/945506.945507}
394}
395
396@INPROCEEDINGS{evans2011r5n,
397 author = {Evans, N.S. and Grothoff, C.},
398 title = {R5n: Randomized recursive routing for restricted-route networks},
399 booktitle = {Network and System Security (NSS), 2011 5th International Conference
400 on},
401 year = {2011},
402 pages = {316--321},
403 organization = {IEEE},
404 file = {:r5n.pdf:PDF}
405}
406
407@INCOLLECTION{evans2012efficient,
408 author = {Evans, Nathan and Polot, Bartlomiej and Grothoff, Christian},
409 title = {Efficient and secure decentralized network size estimation},
410 booktitle = {NETWORKING 2012},
411 publisher = {Springer},
412 year = {2012},
413 pages = {304--317}
414}
415
416@MASTERSTHESIS{evans2011thesis,
417 author = {Nathan S. Evans},
418 title = {Methods for Secure Decentralized Routing in Open Networks},
419 school = {Technische Universit{\"a}t M{\"u}nchen},
420 year = {2011},
421 address = {Garching bei M{\"u}nchen},
422 month = {08/2011},
423 abstract = { The contribution of this thesis is the study and improvement of secure,
424 decentralized, robust routing algorithms for open networks including
425 ad-hoc networks and peer-to-peer (P2P) overlay networks. The main
426 goals for our secure routing algorithm are openness, efficiency,
427 scalability and resilience to various types of attacks. Common P2P
428 routing algorithms trade-off decentralization for security; for instance
429 by choosing whether or not to require a centralized authority to
430 allow peers to join the network. Other algorithms trade scalability
431 for security, for example employing random search or flooding to
432 prevent certain types of attacks. Our design attempts to meet our
433 security goals in an open system, while limiting the performance
434 penalties incurred.
435
436 The first step we took towards designing our routing algorithm was
437 an analysis of the routing algorithm in Freenet. This algorithm is
438 relevant because it achieves efficient (order O(log n)) routing in
439 realistic network topologies in a fully decentralized open network.
440 However, we demonstrate why their algorithm is not secure, as malicious
441 participants are able to severely disrupt the operation of the network.
442 The main difficulty with the Freenet routing algorithm is that for
443 performance it relies on information received from untrusted peers.
444 We also detail a range of proposed solutions, none of which we found
445 to fully fix the problem.
446
447 A related problem for efficient routing in sparsely connected networks
448 is the difficulty in sufficiently populating routing tables. One
449 way to improve connectivity in P2P overlay networks is by utilizing
450 modern NAT traversal techniques. We employ a number of standard NAT
451 traversal techniques in our approach, and also developed and experimented
452 with a novel method for NAT traversal based on ICMP and UDP hole
453 punching. Unlike other NAT traversal techniques ours does not require
454 a trusted third party.
455
456 Another technique we use in our implementation to help address the
457 connectivity problem in sparse networks is the use of distance vector
458 routing in a small local neighborhood. The distance vector variant
459 used in our system employs onion routing to secure the resulting
460 indirect connections. Materially to this design, we discovered a
461 serious vulnerability in the Tor protocol which allowed us to use
462 a DoS attack to reduce the anonymity of the users of this extant
463 anonymizing P2P network. This vulnerability is based on allowing
464 paths of unrestricted length for onion routes through the network.
465 Analyzing Tor and implementing this attack gave us valuable knowledge
466 which helped when designing the distance vector routing protocol
467 for our system.
468
469 Finally, we present the design of our new secure randomized routing
470 algorithm that does not suffer from the various problems we discovered
471 in previous designs. Goals for the algorithm include providing efficiency
472 and robustness in the presence of malicious participants for an open,
473 fully decentralized network without trusted authorities. We provide
474 a mathematical analysis of the algorithm itself and have created
475 and deployed an implementation of this algorithm in GNUnet. In this
476 thesis we also provide a detailed overview of a distributed emulation
477 framework capable of running a large number of nodes using our full
478 code base as well as some of the challenges encountered in creating
479 and using such a testing framework. We present extensive experimental
480 results showing that our routing algorithm outperforms the dominant
481 DHT design in target topologies, and performs comparably in other
482 scenarios.},
483 attachments = {https://gnunet.org/sites/default/files/NET-2011-08-1.pdf},
484 file = {:NET-2011-08-1.pdf:PDF},
485 isbn = {3-937201-26-2},
486 issn = {1868-2642},
487 keywords = {DHT, Freenet, GNUnet, NAT, R5N, Tor},
488 pages = {234},
489 volume = {Dr. rer. nat.}
490}
491
492@CONFERENCE{cset2011evans,
493 author = {Nathan S. Evans and Christian Grothoff},
494 title = {Beyond Simulation: Large-Scale Distributed Emulation of P2P Protocols},
495 booktitle = {4th Workshop on Cyber Security Experimentation and Test (CSET 2011)},
496 year = {2011},
497 address = {San Francisco, California},
498 organization = {USENIX Association},
499 publisher = {USENIX Association},
500 abstract = {This paper presents details on the design and implementation of a
501 scalable framework for evaluating peer-to-peer protocols. Unlike
502 systems based on simulation, emulation-based systems enable the experimenter
503 to obtain data that reflects directly on the concrete implementation
504 in much greater detail. This paper argues that emulation is a better
505 model for experiments with peer-to-peer protocols since it can provide
506 scalability and high flexibility while eliminating the cost of moving
507 from experimentation to deployment. We discuss our unique experience
508 with large-scale emulation using the GNUnet peer-to-peer framework
509 and provide experimental results to support these claims. },
510 file = {:cset2011.pdf:PDF},
511 keywords = {DHT, emulation, GNUnet, scalability, security analysis}
512}
513
514@ARTICLE{nate2012report,
515 author = {Nathan S. Evans and Polot, Bartlomiej and Christian Grothoff},
516 title = {Efficient and Secure Decentralized Network Size Estimation, Tech
517 Report},
518 year = {2012},
519 month = {05/2012},
520 abstract = {The size of a Peer-to-Peer (P2P) network is an important parameter
521 for performance tuning of P2P routing algorithms. This paper introduces
522 and evaluates a new efficient method for participants in an unstructured
523 P2P network to establish the size of the overall network. The presented
524 method is highly efficient, propagating information about the current
525 size of the network to all participants using O(|E|) operations where
526 |E| is the number of edges in the network. Afterwards, all nodes
527 have the same network size estimate, which can be made arbitrarily
528 accurate by averaging results from multiple rounds of the protocol.
529 Security measures are included which make it prohibitively expensive
530 for a typical active participating adversary to significantly manipulate
531 the estimates. This paper includes experimental results that demonstrate
532 the viability, efficiency and accuracy of the protocol.},
533 address = {Garching bei Muenchen},
534 attachments = {https://gnunet.org/sites/default/files/nse-techreport.pdf},
535 file = {:nse2012.pdf:PDF},
536 institution = {Technische Universitaet Muenchen},
537 keywords = {GNUnet, network security, network size estimation, peer-to-peer networking}
538}
539
540@ARTICLE{fall2007network,
541 author = {Fall, Kevin and Varadhan, Kannan},
542 title = {The network simulator (ns-2)},
543 journal = {URL: http://www. isi. edu/nsnam/ns},
544 year = {2007}
545}
546
547@INCOLLECTION{freire2012,
548 author = {Freire, ClaudioDaniel and Quereilhac, Alina and Turletti, Thierry
549 and Dabbous, Walid},
550 title = {Automated Deployment and Customization of Routing Overlays on Planetlab},
551 booktitle = {Testbeds and Research Infrastructure. Development of Networks and
552 Communities},
553 publisher = {Springer Berlin Heidelberg},
554 year = {2012},
555 editor = {Korakis, Thanasis and Zink, Michael and Ott, Maximilian},
556 volume = {44},
557 series = {Lecture Notes of the Institute for Computer Sciences, Social Informatics
558 and Telecommunications Engineering},
559 pages = {240-255},
560 doi = {10.1007/978-3-642-35576-9_21},
561 isbn = {978-3-642-35575-2},
562 keywords = {networking; overlays; PlanetLab; NEPI},
563 url = {http://dx.doi.org/10.1007/978-3-642-35576-9_21}
564}
565
566@INPROCEEDINGS{1209239,
567 author = {Zihui Ge and Figueiredo, D.R. and Jaiswal, S. and Kurose, J. and
568 Towsley, D.},
569 title = {Modeling peer-peer file sharing systems},
570 booktitle = {INFOCOM 2003. Twenty-Second Annual Joint Conference of the IEEE Computer
571 and Communications. IEEE Societies},
572 year = {2003},
573 volume = {3},
574 pages = {2188-2198 vol.3},
575 doi = {10.1109/INFCOM.2003.1209239},
576 file = {:modelling_p2p_file_sharing.pdf:PDF},
577 issn = {0743-166X},
578 keywords = {Internet;distributed processing;file organisation;query processing;centralized
579 indexing;distributed indexing;distributed network applications;file
580 sharing systems;flooded queries;freeloaders;hashing directed queries;mathematical
581 models;peer-peer network;performance degradation;spare capacity;system
582 throughput;Application software;Availability;Computer science;Degradation;Indexing;Mathematical
583 model;Network servers;Peer to peer computing;System performance;Throughput}
584}
585
586@ARTICLE{Giuli2002narses,
587 author = {Thomas J. Giuli and Mary Baker},
588 title = {Narses: A Scalable Flow-Based Network Simulator},
589 journal = {CoRR},
590 year = {2002},
591 volume = {cs.PF/0211024},
592 bibsource = {DBLP, http://dblp.uni-trier.de},
593 ee = {http://arxiv.org/abs/cs.PF/0211024},
594 file = {:Narses_a_scalable_flow_based_network_simulator.pdf:PDF}
595}
596
597@BOOK{mpi,
598 title = {Using MPI-: Portable Parallel Programming with the Message Passing
599 Interface},
600 publisher = {MIT press},
601 year = {1999},
602 author = {Gropp, William and Lusk, Ewing L and Skjellum, Anthony},
603 volume = {1}
604}
605
606@ARTICLE{diecast,
607 author = {Gupta, Diwaker and Vishwanath, Kashi Venkatesh and McNett, Marvin
608 and Vahdat, Amin and Yocum, Ken and Snoeren, Alex and Voelker, Geoffrey
609 M.},
610 title = {DieCast: Testing Distributed Systems with an Accurate Scale Model},
611 journal = {ACM Trans. Comput. Syst.},
612 year = {2011},
613 volume = {29},
614 pages = {4:1--4:48},
615 number = {2},
616 month = may,
617 acmid = {1963560},
618 address = {New York, NY, USA},
619 articleno = {4},
620 doi = {10.1145/1963559.1963560},
621 file = {:diecast.pdf:PDF},
622 issn = {0734-2071},
623 issue_date = {May 2011},
624 keywords = {Virtualization, Xen, network emulation},
625 numpages = {48},
626 publisher = {ACM},
627 url = {http://static.usenix.org/event/nsdi08/tech/full_papers/gupta/gupta_html/}
628}
629
630@INPROCEEDINGS{Gupta2005timewrap,
631 author = {Gupta, Diwaker and Yocum, Kenneth and McNett, Marvin and Snoeren,
632 Alex C. and Vahdat, Amin and Voelker, Geoffrey M.},
633 title = {To infinity and beyond: time warped network emulation},
634 booktitle = {Proceedings of the twentieth ACM symposium on Operating systems principles},
635 year = {2005},
636 series = {SOSP '05},
637 pages = {1--2},
638 address = {New York, NY, USA},
639 publisher = {ACM},
640 acmid = {1118605},
641 doi = {10.1145/1095810.1118605},
642 file = {:emulation_timewrap.pdf:PDF},
643 isbn = {1-59593-079-5},
644 location = {Brighton, United Kingdom},
645 numpages = {2},
646 url = {http://doi.acm.org/10.1145/1095810.1118605}
647}
648
649@INCOLLECTION{gupta2003kelips,
650 author = {Gupta, Indranil and Birman, Ken and Linga, Prakash and Demers, Al
651 and Van Renesse, Robbert},
652 title = {Kelips: Building an efficient and stable P2P DHT through increased
653 memory and background overhead},
654 booktitle = {Peer-to-Peer Systems II},
655 publisher = {Springer},
656 year = {2003},
657 pages = {160--169},
658 file = {:kelips.pdf:PDF}
659}
660
661@INPROCEEDINGS{fuzzybarrier,
662 author = {Gupta, Rajiv},
663 title = {The fuzzy barrier: a mechanism for high speed synchronization of
664 processors},
665 booktitle = {ACM SIGARCH Computer Architecture News},
666 year = {1989},
667 volume = {17},
668 number = {2},
669 pages = {54--63},
670 organization = {ACM}
671}
672
673@ARTICLE{handigol2012reproducible,
674 author = {Handigol, N. and Heller, B. and Jeyakumar, V. and Lantz, B. and McKeown,
675 N.},
676 title = {Reproducible network experiments using container based emulation},
677 journal = {Proc. CoNEXT},
678 year = {2012},
679 __markedentry = {[harsha:1]},
680 file = {:mininet-hifi.pdf:PDF}
681}
682
683@INPROCEEDINGS{mascots2003qi,
684 author = {Qi He and Ammar, M. and Riley, G. and Raj, H. and Fujimoto, R.},
685 title = {Mapping peer behavior to packet-level details: a framework for packet-level
686 simulation of peer-to-peer systems},
687 booktitle = {Modeling, Analysis and Simulation of Computer Telecommunications
688 Systems, 2003. MASCOTS 2003. 11th IEEE/ACM International Symposium
689 on},
690 year = {2003},
691 pages = {71-78},
692 doi = {10.1109/MASCOT.2003.1240644},
693 file = {:p2p_sim_framework.pdf:PDF},
694 issn = {1526-7539},
695 keywords = {discrete event simulation;parallel processing;performance evaluation;transport
696 protocols;Gnutella protocol;Gnutella system performance;discrete-event
697 simulation;network simulator;packet-level simulation;parallelization
698 techniques;peer-to-peer system;underlying network characteristic;Computational
699 modeling;Network servers;Network topology;Peer to peer computing;Proposals;Protocols;Telecommunication
700 computing;Telecommunication traffic;Throughput;Traffic control}
701}
702
703@INCOLLECTION{herrmann2011i2p,
704 author = {Herrmann, Michael and Grothoff, Christian},
705 title = {Privacy-Implications of Performance-Based Peer Selection by Onion-Routers:
706 A Real-World Case Study Using I2P},
707 booktitle = {Privacy Enhancing Technologies},
708 publisher = {Springer Berlin Heidelberg},
709 year = {2011},
710 editor = {Fischer-Hübner, Simone and Hopper, Nicholas},
711 volume = {6794},
712 series = {Lecture Notes in Computer Science},
713 pages = {155-174},
714 doi = {10.1007/978-3-642-22263-4_9},
715 isbn = {978-3-642-22262-7},
716 url = {http://dx.doi.org/10.1007/978-3-642-22263-4_9}
717}
718
719@INPROCEEDINGS{oneswarm,
720 author = {Isdal, Tomas and Piatek, Michael and Krishnamurthy, Arvind and Anderson,
721 Thomas},
722 title = {Privacy-preserving P2P data sharing with OneSwarm},
723 booktitle = {ACM SIGCOMM Computer Communication Review},
724 year = {2010},
725 volume = {40},
726 number = {4},
727 pages = {111--122},
728 organization = {ACM},
729 file = {:oneswarm.pdf:PDF}
730}
731
732@TECHREPORT{jansen2011shadow,
733 author = {Jansen, Rob and Hooper, Nicholas},
734 title = {Shadow: Running Tor in a box for accurate and efficient experimentation},
735 institution = {DTIC Document},
736 year = {2011}
737}
738
739@INPROCEEDINGS{chunksim,
740 author = {Kangasharju, Jussi and Schmidt, Uwe and Bradler, Dirk and Schr\"{o}der-Bernhardi,
741 Julian},
742 title = {ChunkSim: simulating peer-to-peer content distribution},
743 booktitle = {Proceedings of the 2007 spring simulaiton multiconference - Volume
744 1},
745 year = {2007},
746 series = {SpringSim '07},
747 pages = {25--32},
748 address = {San Diego, CA, USA},
749 publisher = {Society for Computer Simulation International},
750 acmid = {1404599},
751 file = {:chunksim.pdf:PDF},
752 isbn = {1-56555-312-8},
753 keywords = {BitTorrent, content distribution, peer-to-peer},
754 location = {Norfolk, Virginia},
755 numpages = {8},
756 url = {http://dl.acm.org/citation.cfm?id=1404595.1404599}
757}
758
759@ARTICLE{ipoib,
760 author = {Kashyap, Vivek},
761 title = {IP over InfiniBand (IPoIB) Architecture},
762 year = {2006},
763 howpublished = {\url{https://tools.ietf.org/html/rfc4392}}
764}
765
766@ARTICLE{knight2012autonetkit,
767 author = {Knight, Simon and Jaboldinov, Askar and Maennel, Olaf and Phillips,
768 Iain and Roughan, Matthew},
769 title = {AutoNetkit: simplifying large scale, open-source network experimentation},
770 journal = {SIGCOMM Comput. Commun. Rev.},
771 year = {2012},
772 volume = {42},
773 pages = {97--98},
774 number = {4},
775 month = aug,
776 acmid = {2377699},
777 address = {New York, NY, USA},
778 doi = {10.1145/2377677.2377699},
779 file = {:autonetkit-small.pdf:PDF},
780 issn = {0146-4833},
781 issue_date = {October 2012},
782 keywords = {automated configuration, emulation, network management},
783 numpages = {2},
784 publisher = {ACM},
785 url = {http://doi.acm.org/10.1145/2377677.2377699}
786}
787
788@INPROCEEDINGS{1565936,
789 author = {Kostoulas, D. and Psaltoulis, D. and Gupta, I. and Birman, K. and
790 Al Demers},
791 title = {Decentralized Schemes for Size Estimation in Large and Dynamic Groups},
792 booktitle = {Network Computing and Applications, Fourth IEEE International Symposium
793 on},
794 year = {2005},
795 pages = {41-48},
796 doi = {10.1109/NCA.2005.15},
797 keywords = {grid computing;peer-to-peer computing;decentralized algorithm;distributed
798 system;dynamic group;grid system;group size estimation;large-scale
799 group;nonfaulty process;peer-to-peer system;probabilistic accuracy;scalable
800 per-process overhead;statistic collection problem;Algorithm design
801 and analysis;Computer science;Delay estimation;Global communication;Large-scale
802 systems;Multicast algorithms;Peer to peer computing;Protocols;Routing;Statistical
803 distributions}
804}
805
806@INPROCEEDINGS{p2prealm,
807 author = {Kotilainen, N. and Vapa, M. and Keltanen, T. and Auvinen, A. and
808 Vuori, J.},
809 title = {P2PRealm - peer-to-peer network simulator},
810 booktitle = {Computer-Aided Modeling, Analysis and Design of Communication Links
811 and Networks, 2006 11th International Workshop on},
812 year = {2006},
813 pages = {93-99},
814 doi = {10.1109/CAMAD.2006.1649724},
815 file = {:p2prealm.pdf:PDF},
816 keywords = {Java;neural nets;peer-to-peer computing;Java native interface;P2PRealm;P2PStudio
817 network visualization tool;neural networks;peer-to-peer network simulator;Computational
818 modeling;Crawlers;Data structures;Information technology;Monitoring;Neural
819 networks;Peer to peer computing;Protocols;Visualization;Workstations}
820}
821
822@INPROCEEDINGS{mininet,
823 author = {Lantz, Bob and Heller, Brandon and McKeown, Nick},
824 title = {A network in a laptop: rapid prototyping for software-defined networks},
825 booktitle = {Proceedings of the 9th ACM SIGCOMM Workshop on Hot Topics in Networks},
826 year = {2010},
827 series = {Hotnets-IX},
828 pages = {19:1--19:6},
829 address = {New York, NY, USA},
830 publisher = {ACM},
831 acmid = {1868466},
832 articleno = {19},
833 doi = {10.1145/1868447.1868466},
834 file = {:mininet.pdf:PDF},
835 isbn = {978-1-4503-0409-2},
836 keywords = {emulation, open-flow, rapid prototyping, software defined networking,
837 virtualization},
838 location = {Monterey, California},
839 numpages = {6},
840 url = {http://doi.acm.org/10.1145/1868447.1868466}
841}
842
843@ARTICLE{leber2009ipv6report,
844 author = {Leber, Mike},
845 title = {Global IPv6 Deployment Progress Report},
846 journal = {Hurricane Electric,[Online]},
847 year = {2009},
848 howpublished = {\url{http://bgp.he.net/ipv6-progress-report.cgi}}
849}
850
851@ARTICLE{fattree,
852 author = {Leiserson, C.E.},
853 title = {Fat-trees: Universal networks for hardware-efficient supercomputing},
854 journal = {Computers, IEEE Transactions on},
855 year = {1985},
856 volume = {C-34},
857 pages = {892-901},
858 number = {10},
859 doi = {10.1109/TC.1985.6312192},
860 issn = {0018-9340},
861 keywords = {computer networks;finite element analysis;parallel processing;trees
862 (mathematics);fat trees;finite-element analysis;general-purpose parallel
863 supercomputer;hardware size;hardware-efficient supercomputing;simultaneous
864 communication;three-dimensional VLSI model;universal networks;universality
865 theorem;Channel capacity;Hardware;Program processors;Routing;Switches;Wires;Fat-trees;VLSI
866 theory;interconnection networks;parallel supercomputing;routing networks;universality}
867}
868
869@INPROCEEDINGS{p2psim_dht_structured,
870 author = {Jinyang Li and Stribling, J. and Morris, R. and Kaashoek, M.F. and
871 Gil, T.M.},
872 title = {A performance vs. cost framework for evaluating DHT design tradeoffs
873 under churn},
874 booktitle = {INFOCOM 2005. 24th Annual Joint Conference of the IEEE Computer and
875 Communications Societies. Proceedings IEEE},
876 year = {2005},
877 volume = {1},
878 pages = {225-236 vol. 1},
879 doi = {10.1109/INFCOM.2005.1497894},
880 file = {:p2psim_structured_DHT.pdf:PDF},
881 issn = {0743-166X},
882 keywords = {bandwidth allocation;file organisation;maintenance engineering;routing
883 protocols;table lookup;telecommunication traffic;distributed hash
884 tables;lookup traffic;maintenance traffic;network bandwidth;performance
885 versus cost framework;proactive flooding;routing protocols;routing
886 table stabilization;stabilization protocols;Artificial intelligence;Bandwidth;Computer
887 science;Costs;Delay;Floods;Gas insulated transmission lines;Laboratories;Routing
888 protocols;Telecommunication traffic}
889}
890
891@INPROCEEDINGS{wids,
892 author = {Shiding Lin and Aimin Pan and Rui Guo and Zheng Zhang},
893 title = {Simulating large-scale P2P systems with the WiDS toolkit},
894 booktitle = {Modeling, Analysis, and Simulation of Computer and Telecommunication
895 Systems, 2005. 13th IEEE International Symposium on},
896 year = {2005},
897 pages = {415-424},
898 doi = {10.1109/MASCOTS.2005.63},
899 file = {:p2p_simulation_with_wids_toolkit.pdf:PDF},
900 issn = {1526-7539},
901 keywords = {large-scale systems;logic simulation;peer-to-peer computing;protocols;relaxation
902 theory;workstation clusters;SMR;WiDS toolkit;commodity PC cluster;critical
903 optimization;distributed protocol;large-scale P2P system;logical
904 time window;lookahead scheme;simulation engine;slow message relaxation;trade
905 simulation accuracy;Debugging;Discrete event simulation;Engines;Large-scale
906 systems;Libraries;Logic testing;Production;Protocols;Runtime;Switches}
907}
908
909@INCOLLECTION{makris2012,
910 author = {Makris, Nikos and Keranidis, Stratos and Giatsios, Dimitris and Korakis,
911 Thanasis and Koutsopoulos, Iordanis and Tassiulas, Leandros and Rakotoarivelo,
912 Thierry and Parmentelat, Thierry},
913 title = {Cross-Testbed Experimentation Using the Planetlab-NITOS Federation},
914 booktitle = {Testbeds and Research Infrastructure. Development of Networks and
915 Communities},
916 publisher = {Springer Berlin Heidelberg},
917 year = {2012},
918 editor = {Korakis, Thanasis and Zink, Michael and Ott, Maximilian},
919 volume = {44},
920 series = {Lecture Notes of the Institute for Computer Sciences, Social Informatics
921 and Telecommunications Engineering},
922 pages = {373-376},
923 doi = {10.1007/978-3-642-35576-9_34},
924 isbn = {978-3-642-35575-2},
925 url = {http://dx.doi.org/10.1007/978-3-642-35576-9_34}
926}
927
928@INPROCEEDINGS{manku2003symphony,
929 author = {Manku, Gurmeet Singh and Bawa, Mayank and Raghavan, Prabhakar and
930 others},
931 title = {Symphony: Distributed hashing in a small world},
932 booktitle = {Proceedings of the 4th USENIX Symposium on Internet Technologies
933 and Systems},
934 year = {2003},
935 volume = {4},
936 pages = {10--10},
937 file = {:symphony.pdf:PDF}
938}
939
940@INPROCEEDINGS{Massoulie:2006:PCS:1146381.1146402,
941 author = {Massouli{\'e}, Laurent and Le Merrer, Erwan and Kermarrec, Anne-Marie
942 and Ganesh, Ayalvadi},
943 title = {Peer counting and sampling in overlay networks: random walk methods},
944 booktitle = {Proceedings of the twenty-fifth annual ACM symposium on Principles
945 of distributed computing},
946 year = {2006},
947 series = {PODC '06},
948 pages = {123--132},
949 address = {New York, NY, USA},
950 publisher = {ACM},
951 acmid = {1146402},
952 doi = {10.1145/1146381.1146402},
953 isbn = {1-59593-384-0},
954 keywords = {expander graphs, peer-to-peer systems, random walks, sampling},
955 location = {Denver, Colorado, USA},
956 numpages = {10},
957 url = {http://doi.acm.org/10.1145/1146381.1146402}
958}
959
960@INCOLLECTION{maymounkov2002kademlia,
961 author = {Maymounkov, Petar and Mazieres, David},
962 title = {Kademlia: A peer-to-peer information system based on the xor metric},
963 booktitle = {Peer-to-Peer Systems},
964 publisher = {Springer},
965 year = {2002},
966 pages = {53--65},
967 file = {:kademlia.pdf:PDF}
968}
969
970@INPROCEEDINGS{peersim,
971 author = {Montresor, A. and Jelasity, M.},
972 title = {PeerSim: A scalable P2P simulator},
973 booktitle = {Peer-to-Peer Computing, 2009. P2P '09. IEEE Ninth International Conference
974 on},
975 year = {2009},
976 pages = {99-100},
977 doi = {10.1109/P2P.2009.5284506},
978 file = {:PeerSim.pdf:PDF},
979 keywords = {peer-to-peer computing;PeerSim;peer-to-peer system;scalable P2P simulator;Discrete
980 event simulation;Engines;Java;Monitoring;Peer to peer computing;Protocols;Scalability;Testing;Topology;Writing}
981}
982
983@ARTICLE{Naicken2007p2psimsurvey,
984 author = {Naicken, S. and Livingston, B. and Basu, A. and Rodhetbhai, S. and
985 Wakeman, I. and Chalmers, D.},
986 title = {The state of peer-to-peer simulators and simulations},
987 journal = {SIGCOMM Comput. Commun. Rev.},
988 year = {2007},
989 volume = {37},
990 pages = {95--98},
991 number = {2},
992 month = mar,
993 acmid = {1232932},
994 address = {New York, NY, USA},
995 doi = {10.1145/1232919.1232932},
996 file = {:TheStateOfP2PSimulatorsAndSimulations.pdf:PDF},
997 issn = {0146-4833},
998 issue_date = {April 2007},
999 keywords = {peer-to-peer, simulator evaluation, simulator usage},
1000 numpages = {4},
1001 publisher = {ACM},
1002 url = {http://doi.acm.org/10.1145/1232919.1232932}
1003}
1004
1005@ARTICLE{nakamoto2008bitcoin,
1006 author = {Nakamoto, Satoshi},
1007 title = {Bitcoin: A peer-to-peer electronic cash system},
1008 journal = {Consulted},
1009 year = {2008},
1010 volume = {1},
1011 pages = {2012}
1012}
1013
1014@ARTICLE{nussbaum2008p2plab,
1015 author = {Nussbaum, Lucas and Richard, Olivier},
1016 title = {Lightweight emulation to study peer-to-peer systems},
1017 journal = {Concurrency and Computation: Practice and Experience},
1018 year = {2008},
1019 volume = {20},
1020 pages = {735--749},
1021 number = {6},
1022 doi = {10.1002/cpe.1242},
1023 file = {:p2plab-cpe.pdf:PDF},
1024 issn = {1532-0634},
1025 keywords = {peer-to-peer, evaluation, emulation, network, virtualization, BitTorrent},
1026 publisher = {John Wiley \& Sons, Ltd.},
1027 url = {http://dx.doi.org/10.1002/cpe.1242}
1028}
1029
1030@INPROCEEDINGS{pizzonia2008netkit,
1031 author = {Pizzonia, Maurizio and Rimondini, Massimo},
1032 title = {Netkit: easy emulation of complex networks on inexpensive hardware},
1033 booktitle = {Proceedings of the 4th International Conference on Testbeds and research
1034 infrastructures for the development of networks \& communities},
1035 year = {2008},
1036 series = {TridentCom '08},
1037 pages = {7:1--7:10},
1038 address = {ICST, Brussels, Belgium, Belgium},
1039 publisher = {ICST (Institute for Computer Sciences, Social-Informatics and Telecommunications
1040 Engineering)},
1041 acmid = {1390585},
1042 articleno = {7},
1043 file = {:netkit.pdf:PDF},
1044 isbn = {978-963-9799-24-0},
1045 keywords = {network emulation, routing, user-mode Linux, virtual laboratories},
1046 location = {Innsbruck, Austria},
1047 numpages = {10},
1048 url = {http://dl.acm.org/citation.cfm?id=1390576.1390585}
1049}
1050
1051@INPROCEEDINGS{planetsim,
1052 author = {Pujol-Ahullo, J. and Garcia-Lopez, P.},
1053 title = {PlanetSim: An extensible simulation tool for peer-to-peer networks
1054 and services},
1055 booktitle = {Peer-to-Peer Computing, 2009. P2P '09. IEEE Ninth International Conference
1056 on},
1057 year = {2009},
1058 pages = {85-86},
1059 doi = {10.1109/P2P.2009.5284504},
1060 file = {:planetsim.pdf:PDF},
1061 keywords = {Java;discrete event simulation;peer-to-peer computing;Java;PlanetSim
1062 tool;discrete event-based simulation framework;peer-to-peer overlay
1063 network;Analytical models;Computational modeling;Computer simulation;Discrete
1064 event simulation;Documentation;Java;Peer to peer computing;Protocols;Statistics;Testing;Java;event-based;peer-to-peer;simulator}
1065}
1066
1067@ARTICLE{opendht,
1068 author = {Rhea, Sean and Godfrey, Brighten and Karp, Brad and Kubiatowicz,
1069 John and Ratnasamy, Sylvia and Shenker, Scott and Stoica, Ion and
1070 Yu, Harlan},
1071 title = {OpenDHT: a public DHT service and its uses},
1072 journal = {SIGCOMM Comput. Commun. Rev.},
1073 year = {2005},
1074 volume = {35},
1075 pages = {73--84},
1076 number = {4},
1077 month = aug,
1078 acmid = {1080102},
1079 address = {New York, NY, USA},
1080 doi = {10.1145/1090191.1080102},
1081 file = {:openDHT.pdf:PDF},
1082 issn = {0146-4833},
1083 issue_date = {October 2005},
1084 keywords = {distributed hash table, peer-to-peer, resource allocation},
1085 numpages = {12},
1086 publisher = {ACM},
1087 url = {http://doi.acm.org/10.1145/1090191.1080102}
1088}
1089
1090@MISC{ritter2001gnutella,
1091 author = {Ritter, Jordan},
1092 title = {Why gnutella can’t scale. no, really},
1093 year = {2001}
1094}
1095
1096@INPROCEEDINGS{macedon,
1097 author = {Rodriguez, A. and Killian, C. and Bhat, S. and Kostic, D. and Vahdat,
1098 A.},
1099 title = {{MACEDON: Methodology for Automatically Creating, Evaluating, and
1100 Designing Overlay Networks",}},
1101 booktitle = {Proc. of the 1st USENIX/ACM Symposium on Networked Systems Design
1102 and Implementation (NSDI)},
1103 year = {\# 2004},
1104 month = mar,
1105 abstract = {{Currently, researchers designing and implementing largescale overlay
1106 services employ disparate techniques at each stage in the production
1107 cycle: design, implementation, experimentation, and evaluation. As
1108 a result, complex and tedious tasks are often duplicated leading
1109 to ine\#ective resource use and di\#culty in fairly comparing competing
1110 algorithms. In this paper, we present MACEDON, an infrastructure
1111 that provides facilities to: i) specify distributed algorithms in
1112 a concise domainspecific...}},
1113 citeulike-article-id = {217372},
1114 citeulike-linkout-0 = {http://citeseer.ist.psu.edu/rodriguez04macedon.html},
1115 citeulike-linkout-1 = {http://citeseer.lcs.mit.edu/rodriguez04macedon.html},
1116 citeulike-linkout-2 = {http://citeseer.ifi.unizh.ch/rodriguez04macedon.html},
1117 citeulike-linkout-3 = {http://citeseer.comp.nus.edu.sg/rodriguez04macedon.html},
1118 file = {:macedon.pdf:PDF},
1119 keywords = {2004, distributed, nsdi, overlays},
1120 posted-at = {2005-06-02 23:45:16},
1121 priority = {0},
1122 url = {http://citeseer.ist.psu.edu/rodriguez04macedon.html}
1123}
1124
1125@ARTICLE{rossi2012modelnet,
1126 author = {Rossi, D. and Veglia, P. and Sammarco, M. and Larroca, F.},
1127 title = {ModelNet-TE: An emulation tool for the study of P2P and traffic engineering
1128 interaction dynamics},
1129 journal = {Peer-to-Peer Networking and Applications},
1130 year = {2012},
1131 pages = {1--19},
1132 file = {:modelnet-si-ppna11.pdf:PDF},
1133 publisher = {Springer}
1134}
1135
1136@INPROCEEDINGS{rowstron2001pastry,
1137 author = {Rowstron, Antony and Druschel, Peter},
1138 title = {Pastry: Scalable, decentralized object location, and routing for
1139 large-scale peer-to-peer systems},
1140 booktitle = {Middleware 2001},
1141 year = {2001},
1142 pages = {329--350},
1143 organization = {Springer},
1144 file = {:pastry.pdf:PDF}
1145}
1146
1147@INPROCEEDINGS{2007sakumoto,
1148 author = {Sakumoto, Y. and Asai, R. and Ohsaki, H. and Imase, M.},
1149 title = {Design and Implementation of Flow-Level Simulator for Performance
1150 Evaluation of Large Scale Networks},
1151 booktitle = {Modeling, Analysis, and Simulation of Computer and Telecommunication
1152 Systems, 2007. MASCOTS '07. 15th International Symposium on},
1153 year = {2007},
1154 pages = {166-172},
1155 doi = {10.1109/MASCOTS.2007.17},
1156 file = {:Sakumoto07_MASCOTS.pdf:PDF},
1157 issn = {1526-7539},
1158 keywords = {Acceleration;Analytical models;Computational modeling;Computer simulation;Differential
1159 equations;Discrete event simulation;Information science;Internet;Large-scale
1160 systems;Mathematical analysis}
1161}
1162
1163@ARTICLE{overlayweaver,
1164 author = {Kazuyuki Shudo and Yoshio Tanaka and Satoshi Sekiguchi},
1165 title = {Overlay Weaver: An overlay construction toolkit },
1166 journal = {Computer Communications },
1167 year = {2008},
1168 volume = {31},
1169 pages = {402 - 412},
1170 number = {2},
1171 note = {<ce:title>Special Issue: Foundation of Peer-to-Peer Computing</ce:title>
1172 },
1173 doi = {10.1016/j.comcom.2007.08.002},
1174 file = {:overlayweaver.pdf:PDF},
1175 issn = {0140-3664},
1176 keywords = {Overlay network},
1177 url = {http://www.sciencedirect.com/science/article/pii/S0140366407002939}
1178}
1179
1180@ARTICLE{usingplanetlab,
1181 author = {Spring, Neil and Peterson, Larry and Bavier, Andy and Pai, Vivek},
1182 title = {Using PlanetLab for network research: myths, realities, and best
1183 practices},
1184 journal = {SIGOPS Oper. Syst. Rev.},
1185 year = {2006},
1186 volume = {40},
1187 pages = {17--24},
1188 number = {1},
1189 month = jan,
1190 acmid = {1113368},
1191 address = {New York, NY, USA},
1192 doi = {10.1145/1113361.1113368},
1193 issn = {0163-5980},
1194 issue_date = {January 2006},
1195 numpages = {8},
1196 publisher = {ACM},
1197 url = {http://doi.acm.org/10.1145/1113361.1113368}
1198}
1199
1200@ARTICLE{stoica2003chord,
1201 author = {Stoica, Ion and Morris, Robert and Liben-Nowell, David and Karger,
1202 David R and Kaashoek, M Frans and Dabek, Frank and Balakrishnan,
1203 Hari},
1204 title = {Chord: a scalable peer-to-peer lookup protocol for internet applications},
1205 journal = {Networking, IEEE/ACM Transactions on},
1206 year = {2003},
1207 volume = {11},
1208 pages = {17--32},
1209 number = {1},
1210 file = {:chord.pdf:PDF},
1211 publisher = {IEEE}
1212}
1213
1214@INPROCEEDINGS{Stutzbach:2006:UCP:1177080.1177105,
1215 author = {Stutzbach, Daniel and Rejaie, Reza},
1216 title = {Understanding churn in peer-to-peer networks},
1217 booktitle = {Proceedings of the 6th ACM SIGCOMM conference on Internet measurement},
1218 year = {2006},
1219 series = {IMC '06},
1220 pages = {189--202},
1221 address = {New York, NY, USA},
1222 publisher = {ACM},
1223 acmid = {1177105},
1224 doi = {10.1145/1177080.1177105},
1225 file = {:understanding_churn.pdf:PDF},
1226 isbn = {1-59593-561-4},
1227 keywords = {Gnutella, bitTorrent, churn, kad, peer-to-peer, session length, uptime},
1228 location = {Rio de Janeriro, Brazil},
1229 numpages = {14},
1230 url = {http://doi.acm.org/10.1145/1177080.1177105}
1231}
1232
1233@MASTERSTHESIS{regex2012szengel,
1234 author = {Maximilian Szengel},
1235 title = {Decentralized Evaluation of Regular Expressions for Capability Discovery
1236 in Peer-to-Peer Networks},
1237 school = {Technische Universitaet Muenchen},
1238 year = {2012},
1239 type = {Masters},
1240 address = {Garching bei Muenchen},
1241 month = {11/2012},
1242 abstract = {This thesis presents a novel approach for decentralized evaluation
1243 of regular expressions for capability discovery in DHT-based overlays.
1244 The system provides support for announcing capabilities expressed
1245 as regular expressions and discovering participants offering adequate
1246 capabilities.
1247
1248 The idea behind our approach is to convert regular expressions into
1249 finite automatons and store the corresponding states and transitions
1250 in a DHT. We show how locally constructed DFA are merged in the DHT
1251 into an NFA without the knowledge of any NFA already present in the
1252 DHT and without the need for any central authority. Furthermore we
1253 present options of optimizing the DFA.
1254
1255 There exist several possible applications for this general approach
1256 of decentralized regular expression evaluation. However, in this
1257 thesis we focus on the application of discovering users that are
1258 willing to provide network access using a specified protocol to a
1259 particular destination.
1260
1261 We have implemented the system for our proposed approach and conducted
1262 a simulation. Moreover we present the results of an emulation of
1263 the implemented system in a cluster.},
1264 file = {:szengel2012ms.pdf:PDF},
1265 howpublished = {\url{https://www.gnunet.org/szengel2012ms}},
1266 keywords = {DFA, DHT, GNUnet, NFA, regular expressions, search},
1267 pages = {100},
1268 volume = {M.S.}
1269}
1270
1271@INPROCEEDINGS{barrier,
1272 author = {Tang, Peiyi and Yew, Pen-Chung},
1273 title = {Processor self-scheduling for multiple-nested parallel loops},
1274 booktitle = {Proceedings of the 1986 international conference on parallel processing},
1275 year = {1986},
1276 pages = {528--535}
1277}
1278
1279@ARTICLE{modelnet,
1280 author = {Vahdat, Amin and Yocum, Ken and Walsh, Kevin and Mahadevan, Priya
1281 and Kosti\'{c}, Dejan and Chase, Jeff and Becker, David},
1282 title = {Scalability and accuracy in a large-scale network emulator},
1283 journal = {SIGOPS Oper. Syst. Rev.},
1284 year = {2002},
1285 volume = {36},
1286 pages = {271--284},
1287 number = {SI},
1288 month = dec,
1289 acmid = {844154},
1290 address = {New York, NY, USA},
1291 doi = {10.1145/844128.844154},
1292 file = {:modelnet-osdi02.pdf:PDF},
1293 issn = {0163-5980},
1294 issue_date = {Winter 2002},
1295 numpages = {14},
1296 publisher = {ACM},
1297 url = {http://doi.acm.org/10.1145/844128.844154}
1298}
1299
1300@INPROCEEDINGS{varga2001omnet++,
1301 author = {Varga, Andr{\'a}s and others},
1302 title = {The OMNeT++ discrete event simulation system},
1303 booktitle = {Proceedings of the European Simulation Multiconference (ESM’2001)},
1304 year = {2001},
1305 volume = {9},
1306 organization = {sn},
1307 file = {:OMNet++.pdf:PDF}
1308}
1309
1310@INPROCEEDINGS{modelnet-timedilation,
1311 author = {Vishwanath, K.V. and Gupta, D. and Vahdat, A. and Yocum, K.},
1312 title = {ModelNet: Towards a datacenter emulation environment},
1313 booktitle = {Peer-to-Peer Computing, 2009. P2P '09. IEEE Ninth International Conference
1314 on},
1315 year = {2009},
1316 pages = {81-82},
1317 doi = {10.1109/P2P.2009.5284497},
1318 file = {:modelnet-timedilation.pdf:PDF},
1319 keywords = {computer centres;computer networks;protocols;virtual machines;ModelNet;complex
1320 network load;data center emulation environment;high-capacity networks;large-scale
1321 experimentation;multicore architectures;network emulator;network
1322 protocols;sophisticated infrastructure software;virtualization;Application
1323 software;Complex networks;Computer architecture;Computer networks;Emulation;Large-scale
1324 systems;Multicore processing;Next generation networking;Protocols;Testing}
1325}
1326
1327@INPROCEEDINGS{weingartner2011slicetime,
1328 author = {Weing{\"a}rtner, Elias and Schmidt, Florian and Vom Lehn, Hendrik
1329 and Heer, Tobias and Wehrle, Klaus},
1330 title = {Slicetime: A platform for scalable and accurate network emulation},
1331 booktitle = {Proceedings of the 8th USENIX conference on Networked systems design
1332 and implementation},
1333 year = {2011},
1334 pages = {19--19},
1335 organization = {USENIX Association},
1336 file = {:slicetime.pdf:PDF}
1337}
1338
1339@ARTICLE{netlab,
1340 author = {White, Brian and Lepreau, Jay and Stoller, Leigh and Ricci, Robert
1341 and Guruprasad, Shashi and Newbold, Mac and Hibler, Mike and Barb,
1342 Chad and Joglekar, Abhijeet},
1343 title = {An integrated experimental environment for distributed systems and
1344 networks},
1345 journal = {SIGOPS Oper. Syst. Rev.},
1346 year = {2002},
1347 volume = {36},
1348 pages = {255--270},
1349 number = {SI},
1350 month = dec,
1351 acmid = {844152},
1352 address = {New York, NY, USA},
1353 doi = {10.1145/844128.844152},
1354 file = {:emulab.pdf:PDF},
1355 issn = {0163-5980},
1356 issue_date = {Winter 2002},
1357 numpages = {16},
1358 publisher = {ACM},
1359 review = {combines simulation, emulation and live networks. Netlab is a descendant
1360 of Emulab},
1361 url = {http://doi.acm.org/10.1145/844128.844152}
1362}
1363
1364@INPROCEEDINGS{tribler,
1365 author = {Zeilemaker, N. and Capota, M. and Bakker, A. and Pouwelse, J.},
1366 title = {Tribler: Search and stream},
1367 booktitle = {Peer-to-Peer Computing (P2P), 2011 IEEE International Conference
1368 on},
1369 year = {2011},
1370 pages = {164-165},
1371 doi = {10.1109/P2P.2011.6038729},
1372 issn = {2161-3559},
1373 keywords = {media streaming;peer-to-peer computing;public domain software;security
1374 of data;video on demand;P2P technology;Tribler;content publishing;content
1375 searching;content sharing;content streaming;live streaming;open-source
1376 software;spam prevention;video on demand;Graphical user interfaces;Open
1377 source software;Peer to peer computing;Protocols;Publishing;Video
1378 on demand}
1379}
1380
1381@ARTICLE{zhao2004tapestry,
1382 author = {Zhao, Ben Y and Huang, Ling and Stribling, Jeremy and Rhea, Sean
1383 C and Joseph, Anthony D and Kubiatowicz, John D},
1384 title = {Tapestry: A resilient global-scale overlay for service deployment},
1385 journal = {Selected Areas in Communications, IEEE Journal on},
1386 year = {2004},
1387 volume = {22},
1388 pages = {41--53},
1389 number = {1},
1390 file = {:tapestry.pdf:PDF},
1391 publisher = {IEEE}
1392}
1393
1394@PROCEEDINGS{DBLP:conf/usenix/2008,
1395 title = {2008 USENIX Annual Technical Conference, Boston, MA, USA, June 22-27,
1396 2008. Proceedings},
1397 year = {2008},
1398 editor = {Rebecca Isaacs and Yuanyuan Zhou},
1399 publisher = {USENIX Association},
1400 bibsource = {DBLP, http://dblp.uni-trier.de},
1401 booktitle = {USENIX Annual Technical Conference},
1402 isbn = {978-1-931971-59-1}
1403}
1404
1405@PROCEEDINGS{DBLP:conf/tridentcom/2012,
1406 title = {Testbeds and Research Infrastructure. Development of Networks and
1407 Communities - 8th International ICST Conference, TridentCom 2012,
1408 Thessanoliki, Greece, June 11-13, 2012, Revised Selected Papers},
1409 year = {2012},
1410 editor = {Thanasis Korakis and Michael Zink and Maximilian Ott},
1411 volume = {44},
1412 series = {Lecture Notes of the Institute for Computer Sciences, Social Informatics
1413 and Telecommunications Engineering},
1414 publisher = {Springer},
1415 bibsource = {DBLP, http://dblp.uni-trier.de},
1416 booktitle = {TRIDENTCOM},
1417 ee = {http://dx.doi.org/10.1007/978-3-642-35576-9},
1418 isbn = {978-3-642-35575-2}
1419}
1420
1421@PROCEEDINGS{DBLP:conf/tridentcom/2010,
1422 title = {Testbeds and Research Infrastructures. Development of Networks and
1423 Communities - 6th International ICST Conference, TridentCom 2010,
1424 Berlin, Germany, May 18-20, 2010, Revised Selected Papers},
1425 year = {2011},
1426 editor = {Thomas Magedanz and Anastasius Gavras and Huu-Thanh Nguyen and Jeffrey
1427 S. Chase},
1428 volume = {46},
1429 series = {Lecture Notes of the Institute for Computer Sciences, Social Informatics
1430 and Telecommunications Engineering},
1431 publisher = {Springer},
1432 bibsource = {DBLP, http://dblp.uni-trier.de},
1433 booktitle = {TRIDENTCOM},
1434 ee = {http://dx.doi.org/10.1007/978-3-642-17851-1},
1435 isbn = {978-3-642-17850-4}
1436}
1437
1438@MISC{infiniband,
1439 title = {Infiniband cluster at LRR-TUM},
1440 howpublished = {\url{http://www.lrr.in.tum.de/Par/arch/infiniband/}}
1441}
1442
1443@MISC{nitos,
1444 title = {NITOS Wireless Testbed - Network Implementation Testbed Laboratory},
1445 howpublished = {\url{http://nitlab.inf.uth.gr/NITlab/index.php/testbed}},
1446 owner = {totakura},
1447 timestamp = {2013.06.03},
1448 url = {http://nitlab.inf.uth.gr/NITlab/index.php/testbed}
1449}
1450
1451@MISC{supermuc,
1452 title = {SuperMUC: Petascale System at Leibniz-Rechenzentrum},
1453 howpublished = {\url{https://www.lrz.de/services/compute/supermuc/}},
1454 year = {2012},
1455 url = {https://www.lrz.de/services/compute/supermuc/}
1456}
1457
1458@PROCEEDINGS{DBLP:conf/acsac/2007,
1459 title = {23rd Annual Computer Security Applications Conference (ACSAC 2007),
1460 December 10-14, 2007, Miami Beach, Florida, USA},
1461 year = {2007},
1462 publisher = {IEEE Computer Society},
1463 bibsource = {DBLP, http://dblp.uni-trier.de},
1464 booktitle = {ACSAC}
1465}
1466
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..31b6a22
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,40 @@
1# This Makefile.am is in the public domain
2bin_PROGRAMS = mping mshd msh test-pty msh-waiter
3
4mping_SOURCES = mping.c
5
6mshd_SOURCES = mshd.c mshd.h util.c util.h mtypes.h \
7 common.h bitmap.c bitmap.h addressmap.c addressmap.h reduce.h reduce.c \
8 server.c pmonitor.c pmonitor.h \
9 ttymodes.h ttymodes.c
10mshd_LDADD = -lgnunetutil -lm
11
12msh_SOURCES = msh.c mtypes.h ttymodes.c ttymodes.h
13msh_LDADD = -lgnunetutil util.$(OBJEXT)
14
15check_PROGRAMS = \
16 test-bitmap \
17 test-addressmap
18
19test_bitmap_SOURCES = test_bitmap.c
20test_bitmap_LDADD = -lgnunetutil bitmap.$(OBJEXT)
21
22test_addressmap_SOURCES = test_addressmap.c
23test_addressmap_LDADD = -lgnunetutil addressmap.$(OBJEXT) util.$(OBJEXT)
24
25TESTS = \
26 test-bitmap \
27 test-addressmap
28
29noinst_PROGRAMS = prop launch
30prop_SOURCES = prop.c
31prop_LDADD = -lgnunetutil
32
33launch_SOURCES = launch.c
34launch_LDADD = -lgnunetutil
35
36test_pty_SOURCES = test_pty.c mtyes.h ttymodes.h ttymodes.c
37test_pty_LDADD = -lgnunetutil
38
39msh_waiter_SOURCES = msh_waiter.c mtypes.h ttymodes.h ttymodes.c
40msh_waiter_LDADD = -lgnunetutil
diff --git a/src/addressmap.c b/src/addressmap.c
new file mode 100644
index 0000000..e161c2e
--- /dev/null
+++ b/src/addressmap.c
@@ -0,0 +1,764 @@
1/**
2 * @file addressmap.c
3 * @brief implementation of address maps
4 * @author Sree Harsha Totakura <sreeharsha@totakura.in>
5 */
6
7#include "common.h"
8#include <gnunet/gnunet_util_lib.h>
9#include "util.h"
10#include "addressmap.h"
11#include "mtypes.h"
12
13#define LOG(kind,...) \
14 GNUNET_log_from (kind, "mshd-addressmap", __VA_ARGS__)
15
16#define LOG_DEBUG(...) LOG(GNUNET_ERROR_TYPE_DEBUG, __VA_ARGS__)
17
18#define LOG_ERROR(...) LOG(GNUNET_ERROR_TYPE_ERROR, __VA_ARGS__)
19
20/**
21 * An address of an instance
22 */
23struct InstanceAddr
24{
25 /**
26 * DLL pointer
27 */
28 struct InstanceAddr *next;
29
30 /**
31 * DLL pointer
32 */
33 struct InstanceAddr *prev;
34
35 /**
36 * the port
37 */
38 uint16_t port;
39
40 /**
41 * the ip address
42 */
43 in_addr_t ip;
44};
45
46
47/**
48 * Instance address information
49 */
50struct InstanceAddrInfo
51{
52 /**
53 * DLL head
54 */
55 struct InstanceAddr *addr_head;
56
57 /**
58 * DLL tail
59 */
60 struct InstanceAddr *addr_tail;
61
62 /**
63 * The place pointer in the AddressMap if this object is added to it. This is
64 * used to invalid the pointer from AddressMap when this object is freed.
65 */
66 struct InstanceAddrInfo **free_ptr;
67
68 /**
69 * Number of addresses in the above array
70 */
71 unsigned int naddrs;
72
73 /**
74 * The MPI id of the instance to whom these addresses belong to
75 */
76 unsigned int rank;
77};
78
79
80/**
81 * Get the 32bit IP addresses from an instance address
82 */
83#define instance_address_ip(iaddr) \
84 (NULL == iaddr ? 0 : ((uint32_t) iaddr->ip))
85
86
87/**
88 * Function to return the port number of an instance address
89 *
90 * @param iaddr the instance address
91 * @return the port number
92 */
93uint16_t
94instance_address_port (struct InstanceAddr *iaddr)
95{
96 return iaddr->port;
97}
98
99/**
100 * Create an instance address structure from its port number and ip address
101 *
102 * @param port the port number
103 * @param ip 32-bit IP address
104 * @return instace address structure
105 */
106struct InstanceAddr *
107instance_address_create_sockaddr_in (uint16_t port, in_addr_t ip)
108{
109 struct InstanceAddr *iaddr;
110
111 iaddr = GNUNET_malloc (sizeof (struct InstanceAddr));
112 iaddr->port = port;
113 iaddr->ip = ip;
114 return iaddr;
115}
116
117
118/**
119 * Releases the resources occupied by the instance address object
120 *
121 * @param iaddr the instance address object
122 */
123void
124instance_address_destroy (struct InstanceAddr *iaddr)
125{
126 free (iaddr);
127}
128
129
130/**
131 * Create an instance address information object
132 *
133 * @param rank the MPI rank of the instance
134 * @return the instance address information object
135 */
136struct InstanceAddrInfo *
137instance_address_info_create (unsigned int rank)
138{
139 struct InstanceAddrInfo *iainfo;
140
141 iainfo = GNUNET_malloc (sizeof (struct InstanceAddrInfo));
142 iainfo->rank = rank;
143 return iainfo;
144}
145
146
147/**
148 * Add an address to the address information object
149 *
150 * @param iainfo the instance information object
151 * @param iaddr the address to add
152 * @return GNUNET_OK if the instance address is added; GNUNET_NO if the given address
153 * is already present (in this case the address object will not be
154 * added)
155 */
156int
157instance_address_info_add_address (struct InstanceAddrInfo *iainfo,
158 struct InstanceAddr *iaddr)
159{
160 struct InstanceAddr *addr;
161
162 addr = iainfo->addr_head;
163 while (NULL != addr)
164 {
165 if (instance_address_ip (iaddr) == instance_address_ip (addr))
166 return GNUNET_NO;
167 if (instance_address_ip (iaddr) < instance_address_ip (addr))
168 break;
169 addr = addr->next;
170 }
171 iainfo->naddrs++;
172 if (NULL == addr)
173 {
174 GNUNET_CONTAINER_DLL_insert_tail (iainfo->addr_head, iainfo->addr_tail, iaddr);
175 return GNUNET_OK;
176 }
177 GNUNET_CONTAINER_DLL_insert_before (iainfo->addr_head, iainfo->addr_tail, addr, iaddr);
178 return GNUNET_OK;
179}
180
181
182/**
183 * Iterate over all addresses in the given instance address info object
184 *
185 * @param iainfo the instance address info object
186 * @param cb the callback to call for each iterated address
187 * @param cls the closure for the above callback
188 * @return GNUNET_OK if the iteration completed successfully; GNUNET_SYSERR if the
189 * iteration was terminated
190 */
191int
192instance_address_info_iterate_addresses (struct InstanceAddrInfo *iainfo,
193 instance_address_info_address_iterate_cb
194 cb,
195 void *cls)
196{
197 struct InstanceAddr *iaddr;
198
199 GNUNET_assert (NULL != cb);
200 iaddr = iainfo->addr_head;
201 while (NULL != iaddr)
202 {
203 if (GNUNET_OK != cb (cls, iaddr->port, iaddr->ip))
204 return GNUNET_SYSERR;
205 iaddr = iaddr->next;
206 }
207 return GNUNET_OK;
208}
209
210
211
212/**
213 * Retrieve the rank of the instance from its address information object
214 *
215 * @param iainfo the address information object
216 * @return the rank of the instance
217 */
218unsigned int
219instance_address_info_get_rank (const struct InstanceAddrInfo *iainfo)
220{
221 return iainfo->rank;
222}
223
224
225/**
226 * Free an instance's address information object along with the instance address
227 * objects
228 *
229 * @param iainfos the instance address information
230 */
231void
232instance_address_info_destroy (struct InstanceAddrInfo *iainfo)
233{
234 struct InstanceAddr *addr;
235
236 while (NULL != (addr = iainfo->addr_head))
237 {
238 GNUNET_CONTAINER_DLL_remove (iainfo->addr_head, iainfo->addr_tail, addr);
239 instance_address_destroy (addr);
240 }
241 if (NULL != iainfo->free_ptr)
242 {
243 GNUNET_assert (iainfo == *iainfo->free_ptr);
244 *iainfo->free_ptr = NULL;
245 }
246 free (iainfo);
247}
248
249
250/**
251 * Handle for address map
252 */
253struct AddressMap
254{
255
256 /**
257 * the size of the following array
258 */
259 unsigned int size;
260
261 /**
262 * The array for address map
263 */
264 struct InstanceAddrInfo *map[0];
265};
266
267
268/**
269 * Create an address map for mapping instances to IP addresses
270 *
271 * @param nproc number of instances
272 * @return address map
273 */
274AddressMap *
275addressmap_create (unsigned int nproc)
276{
277 struct AddressMap *m;
278
279 m = GNUNET_malloc (sizeof (struct AddressMap) + sizeof (struct InstanceAddrInfo
280 *) * nproc);
281 m->size = nproc;
282 return m;
283}
284
285
286/**
287 * Add an address to the address map
288 *
289 * @param m the address map
290 * @param rank the MPI rank of the instance whose address is being added
291 * @param port the port number through which the instance is reachable
292 * @param ip the IP address through which the instance is reachable
293 * @return GNUNET_OK if the instance address is added; GNUNET_NO if the given address
294 * is already present (in this case the address object will not be
295 * added)
296 */
297int
298addressmap_add (AddressMap *m, unsigned int rank, uint16_t port, in_addr_t ip)
299{
300 struct InstanceAddrInfo *iainfo;
301 struct InstanceAddr *iaddr;
302
303 GNUNET_assert (rank < m->size);
304 iainfo = m->map[rank];
305 if (NULL == iainfo)
306 {
307 m->map[rank] = instance_address_info_create (rank);
308 iainfo = m->map[rank];
309 iainfo->free_ptr = &m->map[rank];
310 }
311 iaddr = instance_address_create_sockaddr_in (port, ip);
312 if (GNUNET_NO == instance_address_info_add_address (iainfo, iaddr))
313 {
314 instance_address_destroy (iaddr);
315 return GNUNET_NO;
316 }
317 return GNUNET_OK;
318}
319
320
321/**
322 * Removes the addresses which are present in the Addressmap but not in the
323 * given instance address information object
324 *
325 * @param m the addressmap
326 * @param new the instance address information object
327 * @return the number of addresses in common; GNUNET_SYSERR upon error
328 */
329int
330addressmap_intersect (AddressMap *m, struct InstanceAddrInfo *new)
331{
332 struct InstanceAddrInfo *old;
333 struct InstanceAddr *old_ia;
334 struct InstanceAddr *new_ia;
335 struct InstanceAddr *tmp;
336 unsigned int rank;
337 unsigned int n;
338
339 rank = new->rank;
340 GNUNET_assert (rank < m->size);
341 old = m->map[rank];
342 if (NULL == old)
343 return GNUNET_SYSERR;
344 old_ia = old->addr_head;
345 new_ia = new->addr_head;
346 n = 0;
347 LOG_DEBUG ("Intersecting %u old address with %u new addresses for instance %u\n",
348 old->naddrs, new->naddrs, rank);
349 while (NULL != old_ia)
350 {
351 if ((NULL == new_ia)
352 || (instance_address_ip (old_ia) < instance_address_ip (new_ia)) )
353 {
354 LOG_DEBUG ("Removing old address %u < new address %u\n",
355 instance_address_ip (old_ia), instance_address_ip (new_ia));
356 LOG_DEBUG ("\t old address: %s\n", ip2str (instance_address_ip(old_ia)));
357 LOG_DEBUG ("\t new address: %s\n", ip2str (instance_address_ip(new_ia)));
358 tmp = old_ia->next;
359 GNUNET_CONTAINER_DLL_remove (old->addr_head, old->addr_tail, old_ia);
360 free (old_ia);
361 GNUNET_assert (old->naddrs > 0);
362 old->naddrs--;
363 old_ia = tmp;
364 continue;
365 }
366 if (instance_address_ip (old_ia) > instance_address_ip (new_ia))
367 {
368 new_ia = new_ia->next;
369 continue;
370 }
371 old_ia = old_ia->next;
372 new_ia = new_ia->next;
373 n++;
374 }
375 LOG_DEBUG ("Number of addresses for instance %u after intersection: %u\n",
376 rank, n);
377 return n;
378}
379
380
381/**
382 * Function to iterate over all the instace address info objects present in the
383 * given address map
384 *
385 * @param m the address map
386 * @param cb the iterator callback
387 * @param cls the closure to pass to the iterator callback
388 * @return GNUNET_OK to signify successful completion of the iteration; GNUNET_SYSERR
389 * if the iteration was cancelled
390 */
391int
392addressmap_iterate_instance_address_infos (AddressMap *m,
393 instance_address_info_iterator_cb cb,
394 void *cls)
395{
396 struct InstanceAddrInfo *iainfo;
397 unsigned int cnt;
398
399 for (cnt = 0; cnt < m->size; cnt++)
400 {
401 if (NULL == (iainfo = m->map[cnt]))
402 continue;
403 if (GNUNET_SYSERR == cb (cls, iainfo))
404 return GNUNET_SYSERR;
405 }
406 return GNUNET_OK;
407}
408
409
410/**
411 * Function to iterate over address of an instance in a given address map
412 *
413 * @param m the address map
414 * @param rank the instance rank
415 * @param cb the iterator callback
416 * @param cls the closure for the callback
417 * @return GNUNET_OK if the iteration was successfully completed; GNUNET_SYSERR if the
418 * iteration was aborted in the iteration callback; GNUNET_NO if no
419 * addresses were found in the address map
420 */
421int
422addressmap_iterate_instance_addresses (AddressMap *m, unsigned int rank,
423 instance_address_info_address_iterate_cb
424 cb, void *cls)
425{
426 struct InstanceAddrInfo *iainfo;
427
428 GNUNET_assert (rank < m->size);
429 iainfo = m->map[rank];
430 if (NULL == iainfo)
431 return GNUNET_NO;
432 return instance_address_info_iterate_addresses (iainfo, cb, cls);
433}
434
435
436/**
437 * Destroy the address map. Note that the instance address information object is
438 * not destroyed
439 *
440 * @param m the address map to destroy
441 */
442void
443addressmap_destroy (AddressMap *m)
444{
445 unsigned int cnt;
446
447 for (cnt = 0; cnt < m->size; cnt++)
448 {
449 if (NULL == m->map[cnt])
450 continue;
451 instance_address_info_destroy (m->map[cnt]);
452 }
453 free (m);
454}
455
456
457/**
458 * Serializes an address map into a message which can then be sent to an
459 * instance for merging into its address map
460 *
461 * @param m the address map
462 * @param iaddr_msgs instance addresses. The memory allocated for the instance
463 * address messages is to be freed by the caller after sending the
464 * messages
465 * @return the number of message in iaddr_msgs; GNUNET_SYSERR upon failure (the
466 * contents of iaddr_msgs are left unchanged)
467 */
468int
469addressmap_pack (AddressMap *m, struct MSH_MSG_InstanceAdresses ***iaddr_msgs)
470{
471 struct MSH_MSG_InstanceAdresses **_iaddr_msgs;
472 struct InstanceAddrInfo *iainfo;
473 struct InstanceAddr *iaddr;
474 uint16_t msize;
475 unsigned int cnt;
476 unsigned int n;
477 unsigned int nip;
478
479 n = 0;
480 for (cnt = 0; cnt < m->size; cnt++)
481 {
482 if (NULL == m->map[cnt])
483 {
484 LOG_ERROR ("Addresses for the instance %u is missing\n", cnt);
485 return GNUNET_SYSERR;
486 }
487 n++;
488 }
489 cnt = n;
490 _iaddr_msgs = GNUNET_malloc (sizeof (struct MSH_MSG_InstanceAdresses *) * n);
491 for (cnt = 0; cnt < m->size; cnt++)
492 {
493 struct InstanceAddr *head;
494
495 GNUNET_assert (NULL != (iainfo = m->map[cnt]));
496 msize = sizeof (struct MSH_MSG_InstanceAdresses)
497 + (sizeof (uint32_t) * iainfo->naddrs);
498 _iaddr_msgs[cnt] = GNUNET_malloc (msize);
499 _iaddr_msgs[cnt]->header.size = htons (msize);
500 _iaddr_msgs[cnt]->rank = htons (iainfo->rank);
501 _iaddr_msgs[cnt]->nips = htons (iainfo->naddrs);
502 iaddr = iainfo->addr_head;
503 head = iaddr;
504 _iaddr_msgs[cnt]->port = htons (instance_address_port (head));
505 for (nip = 0; nip < iainfo->naddrs; nip++, iaddr = iaddr->next)
506 {
507 GNUNET_assert (NULL != iaddr);
508 GNUNET_assert (0 != htonl (instance_address_ip (iaddr)));
509 GNUNET_assert (instance_address_port (head) ==
510 instance_address_port (iaddr));
511 _iaddr_msgs[cnt]->ipaddrs[nip] = htonl (instance_address_ip (iaddr));
512 }
513 }
514 *iaddr_msgs = _iaddr_msgs;
515 return m->size;
516}
517
518
519/**
520 * Modifies the given address map to contain the addresses present in it and in
521 * the given instance address message
522 *
523 * @param m the given address map
524 * @param iaddr_msg the message containing instance addresses
525 * @return the number of addresses present in the address map for this instance
526 * after intersecting with the addresses from the given messager;
527 * GNUNET_SYSERR if the given message is not successfully parsed
528 */
529int
530addressmap_intersect_msg (AddressMap *m,
531 const struct MSH_MSG_InstanceAdresses *iaddr_msg)
532{
533 struct InstanceAddr *iaddr;
534 struct InstanceAddrInfo *iainfo;
535 unsigned int rank;
536 unsigned int n;
537 unsigned int cnt;
538 uint16_t size;
539
540 rank = (unsigned int) ntohs (iaddr_msg->rank);
541 n = (unsigned int) ntohs (iaddr_msg->nips);
542 size = ntohs (iaddr_msg->header.size);
543 if (size < (sizeof (struct MSH_MSG_InstanceAdresses)
544 + (sizeof (uint32_t) * n)) )
545 {
546 GNUNET_break (0);
547 return GNUNET_SYSERR;
548 }
549 if (n == 0)
550 {
551 GNUNET_break (0);
552 return GNUNET_SYSERR;
553 }
554 iainfo = instance_address_info_create (rank);
555 for (cnt = 0; cnt < n; cnt++)
556 {
557 iaddr = instance_address_create_sockaddr_in
558 (ntohs (iaddr_msg->port),
559 (in_addr_t) ntohl (iaddr_msg->ipaddrs[cnt]));
560 instance_address_info_add_address (iainfo, iaddr);
561 }
562 n = addressmap_intersect (m, iainfo);
563 instance_address_info_destroy (iainfo);
564 return n;
565}
566
567
568/**
569 * Print the addressmap
570 *
571 * @param m the address map
572 */
573void
574addressmap_print (AddressMap *m)
575{
576 struct InstanceAddrInfo *iainfo;
577 struct InstanceAddr *iaddr;
578 unsigned int cnt;
579 unsigned int dnt;
580
581 for (cnt = 0; cnt < m->size; cnt++)
582 {
583 iainfo = m->map[cnt];
584 GNUNET_assert (NULL != iainfo);
585 iaddr = iainfo->addr_head;
586 for (dnt = 0; dnt < iainfo->naddrs; dnt++, iaddr = iaddr->next)
587 {
588 GNUNET_assert (NULL != iaddr);
589 printf ("Instance %u: %s:%u\n", iainfo->rank, ip2str (iaddr->ip), iaddr->port);
590 }
591 }
592}
593
594
595/**
596 * Function to print addresses of hosts which are running the instances
597 *
598 * @param m the address map
599 * @param fn file name
600 * @param GNUNET_OK upon success; GNUNET_SYSERR upon failure
601 */
602int
603addressmap_write_hosts (AddressMap *m, const char *fn)
604{
605 struct InstanceAddrInfo *iainfo;
606 struct InstanceAddr *iaddr;
607 unsigned int cnt;
608 int ret;
609 FILE *fout;
610
611 ret = GNUNET_SYSERR;
612 fout = fopen (fn, "w+");
613 if (NULL == fout)
614 {
615 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "fopen");
616 return ret;
617 }
618 for (cnt = 0; cnt < m->size; cnt++)
619 {
620 iainfo = m->map[cnt];
621 GNUNET_assert (NULL != iainfo);
622 iaddr = iainfo->addr_head;
623 if (0 > fprintf (fout, "%s\n", ip2str (iaddr->ip)))
624 goto clo_ret;
625 }
626 (void) fflush (fout);
627 ret = GNUNET_OK;
628
629 clo_ret:
630 (void) fclose (fout);
631 return ret;
632}
633
634
635/**
636 * Handle for reverse mapping from IP addresses to instance addresses
637 */
638struct ReverseAddressMap
639{
640 /**
641 * Hash map
642 */
643 struct GNUNET_CONTAINER_MultiHashMap32 *map;
644};
645
646
647/**
648 * Callback for iterating all the instance address info objects present in an
649 * address map
650 *
651 * @param cls the closure passed to addressmap_iterate_instance_address_infos()
652 * @param iainfo the instance address info object
653 * @return MSH_OK to continue iteration; MSH_SYSERR to terminate
654 */
655static int
656reversemap_address_iterator (void *cls, struct InstanceAddrInfo *iainfo)
657{
658 struct ReverseAddressMap *rmap = cls;
659 struct InstanceAddr *iaddr;
660
661 for (iaddr = iainfo->addr_head; NULL != iaddr; iaddr = iaddr->next)
662 {
663 if (GNUNET_SYSERR ==
664 GNUNET_CONTAINER_multihashmap32_put (rmap->map, (uint32_t) iaddr->ip, iaddr,
665 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE))
666 {
667 GNUNET_break (0);
668 return GNUNET_SYSERR;
669 }
670 }
671 return GNUNET_OK;
672}
673
674
675/**
676 * Iterator over hash map entries.
677 *
678 * @param cls closure
679 * @param key current key code
680 * @param value value in the hash map
681 * @return GNUNET_YES if we should continue to
682 * iterate,
683 * GNUNET_NO if not.
684 */
685static int
686reversemap_cleanup_iterator (void *cls, uint32_t key, void *value)
687{
688 struct ReverseAddressMap *rmap = cls;
689
690 GNUNET_break (GNUNET_YES ==
691 GNUNET_CONTAINER_multihashmap32_remove (rmap->map, key, value));
692 return GNUNET_YES;
693}
694
695
696/**
697 * Create a reverse mapping from IP addresses to instance addresses
698 *
699 * @param m the address map
700 * @return reverse address map; NULL upon error
701 */
702struct ReverseAddressMap *
703addressmap_create_reverse_mapping (AddressMap *m)
704{
705 struct ReverseAddressMap *rmap;
706
707 rmap = GNUNET_malloc (sizeof (struct ReverseAddressMap));
708 rmap->map = GNUNET_CONTAINER_multihashmap32_create (m->size * 3);
709 if (GNUNET_SYSERR == addressmap_iterate_instance_address_infos
710 (m, &reversemap_address_iterator, rmap))
711 {
712 reverse_map_destroy (rmap);
713 return NULL;
714 }
715 return rmap;
716}
717
718
719/**
720 * Destroy a reverse address map
721 *
722 * @param rmap the reverse address map
723 */
724void
725reverse_map_destroy (struct ReverseAddressMap *rmap)
726{
727 GNUNET_break (GNUNET_SYSERR !=
728 GNUNET_CONTAINER_multihashmap32_iterate (rmap->map,
729 &reversemap_cleanup_iterator,
730 rmap));
731 GNUNET_CONTAINER_multihashmap32_destroy (rmap->map);
732 GNUNET_free (rmap);
733}
734
735
736/**
737 * Check if the reverse address map contains a given IP addresses
738 *
739 * @param rmap the map
740 * @param ip the IP addresses
741 * @return GNUNET_YES if the given IP exists,
742 * GNUNET_NO if not
743 */
744int
745reversemap_check (struct ReverseAddressMap *rmap, in_addr_t ip)
746{
747 return GNUNET_CONTAINER_multihashmap32_contains (rmap->map, (uint32_t) ip);
748}
749
750
751/**
752 * Find the address through reverse IP mapping
753 *
754 * @param map the map
755 * @param ip the IP
756 * @return NULL if no value was found; note that this is indistinguishable from
757 * values that just happen to be NULL; use "contains" to test for key-value
758 * pairs with value NULL
759 */
760struct InstanceAddr *
761reversemap_lookup (struct ReverseAddressMap *rmap, in_addr_t ip)
762{
763 return GNUNET_CONTAINER_multihashmap32_get (rmap->map, (uint32_t) ip);
764}
diff --git a/src/addressmap.h b/src/addressmap.h
new file mode 100644
index 0000000..5f7ff20
--- /dev/null
+++ b/src/addressmap.h
@@ -0,0 +1,329 @@
1/**
2 * @file addressmap.h
3 * @brief interface for address maps
4 * @author Sree Harsha Totakura <sreeharsha@totakura.in>
5 */
6
7#ifndef ADDRESSMAP_H_
8#define ADDRESSMAP_H_
9
10#include "common.h"
11#include "mtypes.h"
12
13/**
14 * An address of an instance
15 */
16struct InstanceAddr;
17
18
19/**
20 * Instance address information
21 */
22struct InstanceAddrInfo;
23
24
25/**
26 * Create an instance address structure from its port number and ip address
27 *
28 * @param port the port number
29 * @param ip 32-bit IP address
30 * @return instace address structure
31 */
32struct InstanceAddr *
33instance_address_create_sockaddr_in (uint16_t port, in_addr_t ip);
34
35
36/**
37 * Function to return the port number of an instance address
38 *
39 * @param iaddr the instance address
40 * @return the port number
41 */
42uint16_t
43instance_address_port (struct InstanceAddr *iaddr);
44
45
46/**
47 * Create an instance address information object
48 *
49 * @param rank the MPI rank of the instance
50 * @return the instance address information object
51 */
52struct InstanceAddrInfo *
53instance_address_info_create (unsigned int rank);
54
55
56/**
57 * Releases the resources occupied by the instance address object
58 *
59 * @param iaddr the instance address object
60 */
61void
62instance_address_destroy (struct InstanceAddr *iaddr);
63
64
65/**
66 * Add an address to the address information object
67 *
68 * @param iainfo the instance information object
69 * @param iaddr the address to add
70 * @return MSH_OK if the instance address is added; MSH_NO if the given address
71 * is already present (in this case the address object will not be
72 * added)
73 */
74int
75instance_address_info_add_address (struct InstanceAddrInfo *iainfo,
76 struct InstanceAddr *iaddr);
77
78
79/**
80 * Retrieve the rank of the instance from its address information object
81 *
82 * @param iainfo the address information object
83 * @return the rank of the instance
84 */
85unsigned int
86instance_address_info_get_rank (const struct InstanceAddrInfo *iainfo);
87
88
89/**
90 * Free an instance's address information object along with the instance address
91 * objects
92 *
93 * @param iainfos the instance address information
94 */
95void
96instance_address_info_destroy (struct InstanceAddrInfo *iainfos);
97
98
99/**
100 * Callback for iterating all the instance addresses present in an instance
101 * address info object
102 *
103 * @param cls the closure passed to instance_address_info_iterate_addresses()
104 * @param port the port where the instance is listening
105 * @param ip the ip of the instance
106 * @return MSH_OK to continue iteration; MSH_SYSERR to terminate
107 */
108typedef int (*instance_address_info_address_iterate_cb) (void *cls,
109 uint16_t port,
110 in_addr_t ip);
111
112
113/**
114 * Iterate over all addresses in the given instance address info object
115 *
116 * @param iainfo the instance address info object
117 * @param cb the callback to call for each iterated address
118 * @param cls the closure for the above callback
119 * @return MSH_OK if the iteration completed successfully; MSH_SYSERR if the
120 * iteration was terminated
121 */
122int
123instance_address_info_iterate_addresses (struct InstanceAddrInfo *iainfo,
124 instance_address_info_address_iterate_cb
125 cb,
126 void *cls);
127
128
129/**
130 * Opaque handle for address map
131 */
132typedef struct AddressMap AddressMap;
133
134
135/**
136 * Create an address map for mapping instances to IP addresses
137 *
138 * @param nproc number of instances
139 * @return address map
140 */
141AddressMap *
142addressmap_create (unsigned int nproc);
143
144
145/**
146 * Destroy the address map. Note that the instance address information object is
147 * not destroyed
148 *
149 * @param m the address map to destroy
150 */
151void
152addressmap_destroy (AddressMap *m);
153
154
155/**
156 * Add an address to the address map
157 *
158 * @param m the address map
159 * @param rank the MPI rank of the instance whose address is being added
160 * @param port the port number through which the instance is reachable
161 * @param ip the IP address through which the instance is reachable
162 * @return MSH_OK if the instance address is added; MSH_NO if the given address
163 * is already present (in this case the address object will not be
164 * added)
165 */
166int
167addressmap_add (AddressMap *m, unsigned int rank, uint16_t port, in_addr_t ip);
168
169
170/**
171 * Removes the addresses which are present in the Addressmap but not in the
172 * given instance address information object
173 *
174 * @param m the addressmap
175 * @param new the instance address information object
176 * @return the number of addresses in common; MSH_SYSERR upon error
177 */
178int
179addressmap_intersect (AddressMap *m, struct InstanceAddrInfo *new);
180
181
182/**
183 * Callback for iterating all the instance address info objects present in an
184 * address map
185 *
186 * @param cls the closure passed to addressmap_iterate_instance_address_infos()
187 * @param iainfo the instance address info object
188 * @return MSH_OK to continue iteration; MSH_SYSERR to terminate
189 */
190typedef int (*instance_address_info_iterator_cb) (void *cls,
191 struct InstanceAddrInfo *iainfo);
192
193
194/**
195 * Function to iterate over all the instace address info objects present in the
196 * given address map
197 *
198 * @param m the address map
199 * @param cb the iterator callback
200 * @param cls the closure to pass to the iterator callback
201 * @return MSH_OK to signify successful completion of the iteration; MSH_SYSERR
202 * if the iteration was terminated by the callback
203 */
204int
205addressmap_iterate_instance_address_infos (AddressMap *m,
206 instance_address_info_iterator_cb cb,
207 void *cls);
208
209
210/**
211 * Function to iterate over address of an instance in a given address map
212 *
213 * @param m the address map
214 * @param rank the instance rank
215 * @param cb the iterator callback
216 * @param cls the closure for the callback
217 * @return MSH_OK if the iteration was successfully completed; MSH_SYSERR if the
218 * iteration was aborted in the iteration callback; MSH_NO if no
219 * addresses were found in the address map
220 */
221int
222addressmap_iterate_instance_addresses (AddressMap *m, unsigned int rank,
223 instance_address_info_address_iterate_cb
224 cb, void *cls);
225
226
227/**
228 * Serializes an address map into a message which can then be sent to an
229 * instance for merging into its address map
230 *
231 * @param m the address map
232 * @param iaddr_msgs instance addresses. The memory allocated for the instance
233 * address messages is to be freed by the caller after sending the
234 * messages
235 * @return the number of message in iaddr_msgs; MSH_SYSERR upon failure (the
236 * contents of iaddr_msgs are left unchanged)
237 */
238int
239addressmap_pack (AddressMap *m, struct MSH_MSG_InstanceAdresses ***iaddr_msgs);
240
241
242/**
243 * Modifies the given address map to contain the addresses present in it and in
244 * the given instance address message
245 *
246 * @param m the given address map
247 * @param iaddr_msg the message containing instance addresses
248 * @return the number of addresses present in the address map for this instance
249 * after intersecting with the addresses from the given messager;
250 * MSH_SYSERR if the given message is not successfully parsed
251 */
252int
253addressmap_intersect_msg (AddressMap *m,
254 const struct MSH_MSG_InstanceAdresses *iaddr_msg);
255
256
257/**
258 * Print the addressmap
259 *
260 * @param m the address map
261 */
262void
263addressmap_print (AddressMap *m);
264
265
266/**
267 * Function to print addresses of hosts which are running the instances
268 *
269 * @param m the address map
270 * @param fn file name
271 * @param GNUNET_OK upon success; GNUNET_SYSERR upon failure
272 */
273int
274addressmap_write_hosts (AddressMap *m, const char *fn);
275
276
277/**
278 * Handle for reverse mapping from IP addresses to instance addresses
279 */
280struct ReverseAddressMap;
281
282
283/**
284 * Create a reverse mapping from IP addresses to instance addresses
285 *
286 * @param m the address map
287 * @return reverse address map; NULL upon error
288 */
289struct ReverseAddressMap *
290addressmap_create_reverse_mapping (AddressMap *m);
291
292
293/**
294 * Destroy a reverse address map
295 *
296 * @param rmap the reverse address map
297 */
298void
299reverse_map_destroy (struct ReverseAddressMap *rmap);
300
301
302/**
303 * Check if the reverse address map contains a given IP addresses
304 *
305 * @param rmap the map
306 * @param ip the IP addresses
307 * @return GNUNET_YES if the given IP exists,
308 * GNUNET_NO if not
309 */
310int
311reversemap_check (struct ReverseAddressMap *rmap, in_addr_t ip);
312
313
314/**
315 * Find the address through reverse IP mapping
316 *
317 * @param map the map
318 * @param ip the IP
319 * @return NULL if no value was found; note that this is indistinguishable from
320 * values that just happen to be NULL; use "contains" to test for key-value
321 * pairs with value NULL
322 */
323struct InstanceAddr *
324reversemap_lookup (struct ReverseAddressMap *rmap, in_addr_t ip);
325
326
327#endif /* ADDRESSMAP_H_ */
328
329/* End of addressmap.h */
diff --git a/src/bitmap.c b/src/bitmap.c
new file mode 100644
index 0000000..71c27b7
--- /dev/null
+++ b/src/bitmap.c
@@ -0,0 +1,159 @@
1#include "common.h"
2#include "bitmap.h"
3
4/**
5 * @file bitmap
6 * @brief implementation of bitmap array
7 * @author Sree Harsha Totakura <sreeharsha@totakura.in>
8 */
9
10/**
11 * Handler to the bitmap
12 */
13struct BitMap
14{
15 /**
16 * Number of relevant bits in the bitmap
17 */
18 unsigned int len;
19
20 /**
21 * The size of the barray. Should be enough to hold size number of bits
22 */
23 unsigned int array_size;
24
25 /**
26 * The bitmap array
27 */
28 uint32_t barray[0];
29
30};
31
32#define ELE_BITSIZE (8 * sizeof (bm->barray[0]))
33
34/**
35 * Initialize bitmap array
36 *
37 * @param len the number of bits to be present in the bitmap
38 * @return handle to the bitmap
39 */
40struct BitMap *
41bitmap_create (unsigned int len)
42{
43 struct BitMap *bm;
44 unsigned int array_size;
45
46 array_size = (len + ELE_BITSIZE - 1) / ELE_BITSIZE;
47 bm = GNUNET_malloc (sizeof (struct BitMap) + (array_size * sizeof
48 (bm->barray[0])) );
49 bm->len = len;
50 bm->array_size = array_size;
51 return bm;
52}
53
54
55/**
56 * Destroy a bitmap handle and free its resources
57 *
58 * @param bm the bitmap to destroy
59 */
60void
61bitmap_destroy (struct BitMap *bm)
62{
63 free (bm);
64}
65
66
67/**
68 * Clear all the bits in the bitmap
69 *
70 * @param bm the handle to the bitmap
71 */
72void
73bitmap_clear (struct BitMap *bm)
74{
75 (void) memset (bm->barray, 0, bm->array_size * sizeof(bm->barray[0]));
76}
77
78
79/**
80 * Set the bit at given index to the given value
81 *
82 * @param bm the handle to the bitmap
83 * @param id the index of the bit to set
84 * @param val the value; should be either 1 or 0
85 */
86void
87bitmap_set (struct BitMap *bm, unsigned int id, int val)
88{
89 unsigned int off;
90 unsigned int bitidx;
91 typeof (bm->barray[0]) one;
92
93 GNUNET_assert (id < bm->len);
94 GNUNET_assert ( (0 == val) || (1 == val) );
95 off = id / ELE_BITSIZE;
96 bitidx = id % ELE_BITSIZE;
97 GNUNET_assert (off < bm->array_size);
98 one = (typeof (bm->barray[0])) 1; /* cast */
99 one = one << bitidx;
100 if (1 == val)
101 bm->barray[off] |= one;
102 else if (0 != (bm->barray[off] & one))
103 bm->barray[off] ^= one;
104}
105
106
107/**
108 * Checks if the given bit in the bit array is set to not
109 *
110 * @param bm the handle to the bitmap
111 * @param id the index of the bit to set
112 * @return 1 if the given bit is set; 0 otherwise
113 */
114int
115bitmap_isbitset (struct BitMap *bm, unsigned int id)
116{
117 unsigned int off;
118 unsigned int bitidx;
119 typeof (bm->barray[0]) one;
120
121 GNUNET_assert (id < bm->len);
122 off = id / ELE_BITSIZE;
123 bitidx = id % ELE_BITSIZE;
124 GNUNET_assert (off < bm->array_size);
125 one = (typeof (bm->barray[0])) 1; /* cast */
126 return (0 == (bm->barray[off] & (one << bitidx))) ? 0 : 1;
127}
128
129
130/**
131 * Check if all relevant bits in the bitmap are set
132 *
133 * @param bm the handle to the bitmap
134 * @return 1 if all the bits are set; 0 if not
135 */
136int
137bitmap_allset (struct BitMap *bm)
138{
139 unsigned int off;
140 unsigned int bitidx;
141 unsigned int cnt;
142 typeof (bm->barray[0]) max;
143
144 max = (typeof (bm->barray[0])) 0;
145 max = max - 1;
146 off = bm->len / ELE_BITSIZE;
147 bitidx = bm->len % ELE_BITSIZE;
148 GNUNET_assert (off < bm->array_size);
149 for (cnt = 0; cnt < off; cnt ++)
150 {
151 if (0 != (max ^ bm->barray[cnt]))
152 return 0;
153 }
154 if (0 == bitidx)
155 return 1;
156 max = (typeof (bm->barray[0])) 1;
157 max = (max << bitidx) - 1;
158 return (max == (bm->barray[off] & max)) ? 1 : 0;
159}
diff --git a/src/bitmap.h b/src/bitmap.h
new file mode 100644
index 0000000..d31758b
--- /dev/null
+++ b/src/bitmap.h
@@ -0,0 +1,80 @@
1/**
2 * @file bitmap.h
3 * @brief interface for bitmap array
4 * @author Sree Harsha Totakura <sreeharsha@totakura.in>
5 */
6
7#ifndef BITMAP_H_
8#define BITMAP_H_
9
10
11/**
12 * Opaque handle to the bitmap
13 */
14struct BitMap;
15
16
17/**
18 * Initialize bitmap array
19 *
20 * @param len the number of bits to be present in the bitmap
21 * @return handle to the bitmap
22 */
23struct BitMap *
24bitmap_create (unsigned int len);
25
26
27/**
28 * Destroy a bitmap handle and free its resources
29 *
30 * @param bm the bitmap to destroy
31 */
32void
33bitmap_destroy (struct BitMap *bm);
34
35
36/**
37 * Clear all the bits in the bitmap
38 *
39 * @param bm the handle to the bitmap
40 */
41void
42bitmap_clear (struct BitMap *bm);
43
44
45/**
46 * Set the bit at given index to the given value
47 *
48 * @param bm the handle to the bitmap
49 * @param id the index of the bit to set
50 * @param val the value; should be either 1 or 0
51 */
52void
53bitmap_set (struct BitMap *bm, unsigned int id, int val);
54
55
56/**
57 * Checks if the given bit in the bit array is set to not
58 *
59 * @param bm the handle to the bitmap
60 * @param id the index of the bit to set
61 * @return 1 if the given bit is set; 0 otherwise
62 */
63int
64bitmap_isbitset (struct BitMap *bm, unsigned int id);
65
66
67/**
68 * Check if all relevant bits in the bitmap are set
69 *
70 * @param bm the handle to the bitmap
71 * @return 1 if all the bits are set; 0 if not
72 */
73int
74bitmap_allset (struct BitMap *bm);
75
76
77
78#endif /* #ifndef BITMAP_H_ */
79
80/* End of bitmap.h */
diff --git a/src/common.h b/src/common.h
new file mode 100644
index 0000000..c7d1c93
--- /dev/null
+++ b/src/common.h
@@ -0,0 +1,39 @@
1/**
2 * @file common.h
3 * @brief common header which is to be included in all sources
4 * @author Sree Harsha Totakura <sreeharsha@totakura.in>
5 */
6
7#ifndef COMMON_H_
8#define COMMON_H_
9
10#ifndef _GNU_SOURCE
11#define _GNU_SOURCE 1
12#endif
13
14#include "../config.h"
15#define HAVE_USED_CONFIG_H
16#include <gnunet/platform.h>
17#include <gnunet/gnunet_util_lib.h>
18
19#define MSH_close(fd) \
20 do {if (0 != close (fd)) \
21 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "close"); \
22 } while (0)
23
24
25/**
26 * Environmental variable determining the UNIX domain socket used for
27 * communication between MSH and local MSHD processes
28 */
29#define MSHD_SOCK_NAME "MSHD_SOCK"
30
31/**
32 * Environmental variable determining the file where the addresses of available
33 * hosts are written to
34 */
35#define MSHD_HOSTSFILE "MP_SAVEHOSTFILE"
36
37#endif /* COMMON_H_ */
38
39/* End of common.h */
diff --git a/src/launch.c b/src/launch.c
new file mode 100644
index 0000000..0d3a47e
--- /dev/null
+++ b/src/launch.c
@@ -0,0 +1,44 @@
1#include "common.h"
2#include <gnunet/gnunet_util_lib.h>
3
4int main ()
5{
6 struct GNUNET_OS_Process *proc;
7 struct GNUNET_DISK_PipeHandle *pin;
8 struct GNUNET_DISK_PipeHandle *pout;
9 struct GNUNET_DISK_FileHandle *fin;
10 struct GNUNET_DISK_FileHandle *fout;
11 char *cmd[] = {"./prop", NULL};
12 char *str = "Hello World\n";
13 char buf[256];
14 ssize_t rx;
15
16 GNUNET_log_setup ("msh-launch", NULL, NULL);
17 pin = GNUNET_DISK_pipe (GNUNET_NO, GNUNET_NO, 0, 0);
18 pout = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_NO, 0, 0);
19 proc = GNUNET_OS_start_process_vap (GNUNET_NO,
20 GNUNET_OS_INHERIT_STD_NONE,
21 pin,
22 pout,
23 NULL,
24 cmd[0], cmd);
25 GNUNET_assert (NULL != proc);
26 fin = GNUNET_DISK_pipe_detach_end (pin, GNUNET_DISK_PIPE_END_WRITE);
27 fout = GNUNET_DISK_pipe_detach_end (pout, GNUNET_DISK_PIPE_END_READ);
28 GNUNET_assert (GNUNET_OK == GNUNET_DISK_pipe_close (pin));
29 GNUNET_assert (GNUNET_OK == GNUNET_DISK_pipe_close (pout));
30 GNUNET_break (strlen (str)
31 == GNUNET_DISK_file_write_blocking (fin, str, strlen (str)));
32 errno = 0;
33 rx = GNUNET_DISK_file_read (fout, buf, sizeof (buf));
34 if (0 != errno)
35 perror ("read");
36 GNUNET_assert (GNUNET_SYSERR != rx);
37 if (0 == rx)
38 {
39 GNUNET_break (0);
40 return 1;
41 }
42 fwrite (buf, rx, 1, stdout);
43 return 0;
44}
diff --git a/src/launch_ll.c b/src/launch_ll.c
new file mode 100644
index 0000000..bfad467
--- /dev/null
+++ b/src/launch_ll.c
@@ -0,0 +1,47 @@
1#define _GNU_SOURCE
2
3#include <unistd.h>
4#include <fcntl.h>
5#include <stdlib.h>
6#include <assert.h>
7#include <string.h>
8#include <stdio.h>
9
10int main ()
11{
12 int inpipe[2];
13 int outpipe[2];
14 pid_t cid;
15 int status;
16 char *str = "Hello World\n";
17 char buf[256];
18 ssize_t rx;
19
20 assert (0 == pipe2 (inpipe, O_CLOEXEC));
21 assert (0 == pipe2 (outpipe, O_CLOEXEC));
22 cid = fork ();
23 assert (-1 != cid);
24 if (0 == cid)
25 {
26 assert (0 == close (0));
27 assert (-1 != (dup2 (inpipe[0], 0)));
28 assert (0 == close (inpipe[1]));
29 assert (0 == close (inpipe[0]));
30
31 assert (0 == close (1));
32 assert (-1 != (dup2 (outpipe[1], 1)));
33 assert (0 == close (outpipe[1]));
34 assert (0 == close (outpipe[0]));
35
36 (void) execlp ("./prop", "prop", (char *) NULL);
37 assert (0);
38 }
39 assert (strlen (str) == write (inpipe[1], str, strlen (str)));
40 rx = read (outpipe[0], buf, sizeof (buf));
41 assert (-1 != rx);
42 if (rx < sizeof (buf))
43 buf[rx] = '\0';
44 printf ("%.256s", buf);
45 assert (cid == wait (&status));
46 return 0;
47}
diff --git a/src/mping.c b/src/mping.c
new file mode 100644
index 0000000..92ceef6
--- /dev/null
+++ b/src/mping.c
@@ -0,0 +1,424 @@
1/*
2 * MPI ping program
3 *
4 * Patterned after the example in the Quadrics documentation
5 * Downloaded from: http://www.open-mpi.org/community/lists/devel/att-0116/mpi-ping.c
6 */
7
8#define MPI_ALLOC_MEM 0
9#include <stdio.h>
10#include <stdlib.h>
11#include <string.h>
12#include <unistd.h>
13#include <sys/select.h>
14
15#include <getopt.h>
16
17#include <mpi.h>
18
19static int str2size(char *str)
20{
21 int size;
22 char mod[32];
23
24 switch (sscanf(str, "%d%1[mMkK]", &size, mod)) {
25 case 1:
26 return (size);
27
28 case 2:
29 switch (*mod) {
30 case 'm':
31 case 'M':
32 return (size << 20);
33
34 case 'k':
35 case 'K':
36 return (size << 10);
37
38 default:
39 return (size);
40 }
41
42 default:
43 return (-1);
44 }
45}
46
47
48static void usage(void)
49{
50 fprintf(stderr,
51 "Usage: mpi-ping [flags] <min bytes> [<max bytes>] [<inc bytes>]\n"
52 " mpi-ping -h\n");
53 exit(EXIT_FAILURE);
54}
55
56
57static void help(void)
58{
59 printf
60 ("Usage: mpi-ping [flags] <min bytes> [<max bytes>] [<inc bytes>]\n"
61 "\n" " Flags may be any of\n"
62 " -B use blocking send/recv\n"
63 " -C check data\n"
64 " -O overlapping pings\n"
65 " -W perform warm-up phase\n"
66 " -r number repetitions to time\n"
67 " -A use MPI_Alloc_mem to register memory\n"
68 " -h print this info\n" "\n"
69 " Numbers may be postfixed with 'k' or 'm'\n\n");
70
71 exit(EXIT_SUCCESS);
72}
73
74
75int main(int argc, char *argv[])
76{
77 MPI_Status status;
78 MPI_Request recv_request;
79 MPI_Request send_request;
80 unsigned char *rbuf;
81 unsigned char *tbuf;
82 int c;
83 int i;
84 int bytes;
85 int nproc;
86 int peer;
87 int proc;
88 int r;
89 int tag = 0x666;
90
91 /*
92 * default options / arguments
93 */
94 int reps = 10000;
95 int blocking = 0;
96 int check = 0;
97 int overlap = 0;
98 int warmup = 0;
99 int inc_bytes = 0;
100 int max_bytes = 0;
101 int min_bytes = 0;
102 int alloc_mem = 0;
103
104 MPI_Init(&argc, &argv);
105 MPI_Comm_rank(MPI_COMM_WORLD, &proc);
106 MPI_Comm_size(MPI_COMM_WORLD, &nproc);
107
108 while ((c = getopt(argc, argv, "BCOWAr:h")) != -1) {
109 switch (c) {
110
111 case 'B':
112 blocking = 1;
113 break;
114
115 case 'C':
116 check = 1;
117 break;
118
119 case 'O':
120 overlap = 1;
121 break;
122
123 case 'W':
124 warmup = 1;
125 break;
126
127
128 case 'A':
129 alloc_mem=1;
130 break;
131
132
133 case 'r':
134 if ((reps = str2size(optarg)) <= 0) {
135 usage();
136 }
137 break;
138
139 case 'h':
140 help();
141
142 default:
143 usage();
144 }
145 }
146
147 if (optind == argc) {
148 min_bytes = 0;
149 } else if ((min_bytes = str2size(argv[optind++])) < 0) {
150 usage();
151 }
152
153 if (optind == argc) {
154 max_bytes = min_bytes;
155 } else if ((max_bytes = str2size(argv[optind++])) < min_bytes) {
156 usage();
157 }
158
159 if (optind == argc) {
160 inc_bytes = 0;
161 } else if ((inc_bytes = str2size(argv[optind++])) < 0) {
162 usage();
163 }
164
165 if (nproc == 1) {
166 exit(EXIT_SUCCESS);
167 }
168
169 #if MPI_ALLOC_MEM
170 if(alloc_mem) {
171 MPI_Alloc_mem(max_bytes ? max_bytes: 8, MPI_INFO_NULL, &rbuf);
172 MPI_Alloc_mem(max_bytes ? max_bytes: 8, MPI_INFO_NULL, &tbuf);
173 }
174 else {
175 #endif
176 if ((rbuf = (unsigned char *) malloc(max_bytes ? max_bytes : 8)) == NULL) {
177 perror("malloc");
178 exit(EXIT_FAILURE);
179 }
180 if ((tbuf = (unsigned char *) malloc(max_bytes ? max_bytes : 8)) == NULL) {
181 perror("malloc");
182 exit(EXIT_FAILURE);
183 }
184 #if MPI_ALLOC_MEM
185 }
186 #endif
187
188 if (check) {
189 for (i = 0; i < max_bytes; i++) {
190 tbuf[i] = i & 255;
191 rbuf[i] = 0;
192 }
193 }
194
195 if (proc == 0) {
196 if (overlap) {
197 printf("mpi-ping: overlapping ping-pong\n");
198 } else if (blocking) {
199 printf("mpi-ping: ping-pong (using blocking send/recv)\n");
200 } else {
201 printf("mpi-ping: ping-pong\n");
202 }
203 if (check) {
204 printf("data checking enabled\n");
205 }
206 printf("nprocs=%d, reps=%d, min bytes=%d, max bytes=%d inc bytes=%d\n",
207 nproc, reps, min_bytes, max_bytes, inc_bytes);
208 fflush(stdout);
209 }
210
211 MPI_Barrier(MPI_COMM_WORLD);
212
213 peer = proc ^ 1;
214
215 if ((peer < nproc) && (peer & 1)) {
216 printf("%d pings %d\n", proc, peer);
217 fflush(stdout);
218 }
219
220 MPI_Barrier(MPI_COMM_WORLD);
221
222 if (warmup) {
223
224 if (proc == 0) {
225 puts("warm-up phase");
226 fflush(stdout);
227 }
228
229 for (r = 0; r < reps; r++) {
230 if (peer >= nproc) {
231 break;
232 }
233 MPI_Irecv(rbuf, max_bytes, MPI_BYTE, peer, tag, MPI_COMM_WORLD,
234 &recv_request);
235 MPI_Isend(tbuf, max_bytes, MPI_BYTE, peer, tag, MPI_COMM_WORLD,
236 &send_request);
237 MPI_Wait(&send_request, &status);
238 MPI_Wait(&recv_request, &status);
239 }
240
241 if (proc == 0) {
242 puts("warm-up phase done");
243 fflush(stdout);
244 }
245 }
246
247 MPI_Barrier(MPI_COMM_WORLD);
248
249 /*
250 * Main loop
251 */
252
253 for (bytes = min_bytes; bytes <= max_bytes;
254 bytes = inc_bytes ? bytes + inc_bytes : bytes ? 2 * bytes : 1) {
255
256 double t = 0.0;
257 double tv[2];
258
259 r = reps;
260
261 MPI_Barrier(MPI_COMM_WORLD);
262
263 if (peer < nproc) {
264
265 if (overlap) {
266
267 /*
268 * MPI_Isend / MPI_Irecv overlapping ping-pong
269 */
270
271 tv[0] = MPI_Wtime();
272
273 for (r = 0; r < reps; r++) {
274
275 MPI_Irecv(rbuf, bytes, MPI_BYTE, peer, tag,
276 MPI_COMM_WORLD, &recv_request);
277 MPI_Isend(tbuf, bytes, MPI_BYTE, peer, tag,
278 MPI_COMM_WORLD, &send_request);
279 MPI_Wait(&send_request, &status);
280 MPI_Wait(&recv_request, &status);
281
282 if (check) {
283 for (i = 0; i < bytes; i++) {
284 if (rbuf[i] != (unsigned char)(i & 255)) {
285 fprintf(stderr, "Error: index=%d sent %d received %d\n",
286 i, ((unsigned char)i)&255, (unsigned char)rbuf[i]);
287 }
288 rbuf[i] = 0;
289 }
290 }
291 }
292
293 tv[1] = MPI_Wtime();
294
295 } else if (blocking) {
296
297 /*
298 * MPI_Send / MPI_Recv ping-pong
299 */
300
301 tv[0] = MPI_Wtime();
302
303 if (peer < nproc) {
304 if (proc & 1) {
305 r--;
306 MPI_Recv(rbuf, bytes, MPI_BYTE, peer, tag,
307 MPI_COMM_WORLD, &status);
308
309 if (check) {
310 for (i = 0; i < bytes; i++) {
311 if (rbuf[i] != (unsigned char)(i & 255)) {
312 fprintf(stderr, "Error: index=%d sent %d received %d\n",
313 i, ((unsigned char)i)&255, (unsigned char)rbuf[i]);
314 }
315 rbuf[i] = 0;
316 }
317 }
318 }
319
320 while (r-- > 0) {
321
322 MPI_Send(tbuf, bytes, MPI_BYTE, peer, tag,
323 MPI_COMM_WORLD);
324 MPI_Recv(rbuf, bytes, MPI_BYTE, peer, tag,
325 MPI_COMM_WORLD, &status);
326
327 if (check) {
328 for (i = 0; i < bytes; i++) {
329 if (rbuf[i] != (unsigned char)(i & 255)) {
330 fprintf(stderr, "Error: index=%d sent %d received %d\n",
331 i, ((unsigned char)i)&255, (unsigned char)rbuf[i]);
332 }
333 rbuf[i] = 0;
334 }
335 }
336 }
337
338 if (proc & 1) {
339 MPI_Send(tbuf, bytes, MPI_BYTE, peer, tag,
340 MPI_COMM_WORLD);
341 }
342 }
343
344 tv[1] = MPI_Wtime();
345
346 } else {
347
348 /*
349 * MPI_Isend / MPI_Irecv ping-pong
350 */
351
352 tv[0] = MPI_Wtime();
353
354 if (peer < nproc) {
355 if (proc & 1) {
356 r--;
357 MPI_Irecv(rbuf, bytes, MPI_BYTE, peer, tag,
358 MPI_COMM_WORLD, &recv_request);
359 MPI_Wait(&recv_request, &status);
360
361 if (check) {
362 for (i = 0; i < bytes; i++) {
363 if (rbuf[i] != (unsigned char)(i & 255)) {
364 fprintf(stderr, "Error: index=%d sent %d received %d\n",
365 i, ((unsigned char)i)&255, (unsigned char)rbuf[i]);
366 }
367 rbuf[i] = 0;
368 }
369 }
370 }
371
372 while (r-- > 0) {
373
374 MPI_Isend(tbuf, bytes, MPI_BYTE, peer, tag,
375 MPI_COMM_WORLD, &send_request);
376 MPI_Wait(&send_request, &status);
377 MPI_Irecv(rbuf, bytes, MPI_BYTE, peer, tag,
378 MPI_COMM_WORLD, &recv_request);
379 MPI_Wait(&recv_request, &status);
380
381 if (check) {
382 for (i = 0; i < bytes; i++) {
383 if (rbuf[i] != (unsigned char)(i & 255)) {
384 fprintf(stderr, "Error: index=%d sent %d received %d\n",
385 i, ((unsigned char)i)&255, (unsigned char)rbuf[i]);
386 }
387 rbuf[i] = 0;
388 }
389 }
390 }
391
392 if (proc & 1) {
393 MPI_Isend(tbuf, bytes, MPI_BYTE, peer, tag,
394 MPI_COMM_WORLD, &send_request);
395 MPI_Wait(&send_request, &status);
396 }
397 }
398
399 tv[1] = MPI_Wtime();
400 }
401
402 /*
403 * Calculate time interval in useconds (half round trip)
404 */
405
406 t = (tv[1] - tv[0]) * 1000000.0 / (2 * reps);
407
408 }
409
410 MPI_Barrier(MPI_COMM_WORLD);
411
412 if ((peer < nproc) && (peer & 1)) {
413 printf("%3d pinged %3d: %8d bytes %9.2f uSec %8.2f MB/s\n",
414 proc, peer, bytes, t, bytes / (t));
415 fflush(stdout);
416 }
417 }
418
419 MPI_Barrier(MPI_COMM_WORLD);
420 MPI_Finalize();
421
422 return EXIT_SUCCESS;
423}
424
diff --git a/src/msh.c b/src/msh.c
new file mode 100644
index 0000000..1dc025d
--- /dev/null
+++ b/src/msh.c
@@ -0,0 +1,938 @@
1/**
2 * @file msh.c
3 * @brief program to launch remote processes through MSH. This program is
4 * to be started by the MSH Daemon or by any process in the process
5 * subtree having the MSH Daemon as a parent process.
6 * @author Sree Harsha Totakura <sreeharsha@totakura.in>
7 */
8
9#include "common.h"
10#include <gnunet/gnunet_util_lib.h>
11#include "termios.h"
12#include "mtypes.h"
13#include "util.h"
14
15#define LOG(kind,...) \
16 GNUNET_log (kind, __VA_ARGS__)
17
18#define LOG_DEBUG(...) LOG(GNUNET_ERROR_TYPE_DEBUG, __VA_ARGS__)
19
20#define LOG_ERROR(...) LOG(GNUNET_ERROR_TYPE_ERROR, __VA_ARGS__)
21
22/**
23 * Configuration section for connection to local MSHD
24 */
25#define MSHD_LOCAL "MSHD-LOCAL"
26
27/**
28 * Configuration section for connection to remote MSHD
29 */
30#define MSHD_REMOTE "MSHD-REMOTE"
31
32/**
33 * The message queue for sending messages to the controller service
34 */
35struct MessageQueue
36{
37 /**
38 * next pointer for DLL
39 */
40 struct MessageQueue *next;
41
42 /**
43 * prev pointer for DLL
44 */
45 struct MessageQueue *prev;
46
47 /**
48 * The message to be sent
49 */
50 struct GNUNET_MessageHeader *msg;
51};
52
53
54/**
55 * Context information for a connection
56 */
57struct ConnCtx
58{
59 /**
60 * The transmit handle
61 */
62 struct GNUNET_CLIENT_TransmitHandle *tx;
63
64 /**
65 * The client connection handle
66 */
67 struct GNUNET_CLIENT_Connection *conn;
68
69 /**
70 * configuration used to obtain this connection
71 */
72 struct GNUNET_CONFIGURATION_Handle *cfg;
73
74 /**
75 * DLL head for the message queue
76 */
77 struct MessageQueue *mq_head;
78
79 /**
80 * DLL tail for the message queue
81 */
82 struct MessageQueue *mq_tail;
83
84 /**
85 * retry backoff time for this connection
86 */
87 struct GNUNET_TIME_Relative backoff;
88};
89
90
91/**
92 * context for the connection to parent MSHD
93 */
94static struct ConnCtx ctx_local;
95
96/**
97 * context for the connection to remote MSHD
98 */
99static struct ConnCtx ctx_remote;
100
101/**
102 * file handle for the stdin
103 */
104static struct GNUNET_DISK_FileHandle *fh_stdin;
105
106/**
107 * file handle for stdout
108 */
109static struct GNUNET_DISK_FileHandle *fh_stdout;
110
111/**
112 * file handle for stdout
113 */
114static struct GNUNET_DISK_FileHandle *fh_stderr;
115
116/**
117 * The command string (cmd + parameters)
118 */
119static char *cmdstr;
120
121/**
122 * Program help text
123 */
124static char *help_text =
125 "MSH utility to lauch remote programs\n"
126 "Usage: msh <ip-address> <cmd> [arg] ... \n";
127
128/**
129 * Buffer used to read data from input streams
130 */
131static char recv_buf[GNUNET_SERVER_MAX_MESSAGE_SIZE];
132
133/**
134 * Handle for a test to check if MSHD is running in a mode accepting remote commands.
135 */
136struct GNUNET_CLIENT_TestHandle *test;
137
138/**
139 * length of the cmdstr
140 */
141static size_t cmdstr_len;
142
143/**
144 * Task to forward stdin to MSHD
145 */
146static GNUNET_SCHEDULER_TaskIdentifier task_fwd_stdin;
147
148/**
149 * Shutdown task to disconnect client connections
150 */
151static GNUNET_SCHEDULER_TaskIdentifier task_shutdown;
152
153/**
154 * flag to indicate successful completion by setting it to GNUNET_OK
155 */
156static int result;
157
158/**
159 * different states
160 */
161enum State
162{
163 /**
164 * Address lookup of the remote instance
165 */
166 STATE_LOOKUP,
167
168 /**
169 * Remote command is delivered to remote MSHD
170 */
171 STATE_DELIVER_CMD,
172
173 /**
174 * Get authorization credential from parent MSHD
175 */
176 STATE_GET_CRED,
177
178 /**
179 * stdin and stdout streams are forwarded to and from the MSHD
180 */
181 STATE_FORWARD_STREAMS,
182
183} state;
184
185
186/**
187 * Terminal window size information
188 */
189static struct winsize ws;
190
191/**
192 * Terminal settings
193 */
194static struct termios tio;
195
196/**
197 * The ip address of the remote node
198 */
199static in_addr_t target;
200
201/**
202 * The port number where the MSHD is listening on target host
203 */
204static uint16_t target_port;
205
206/**
207 * Do not allocate pseudo-tty
208 */
209static int disable_pty;
210
211/**
212 * Are we capable of allocating pseudo-tty
213 */
214static int can_pty;
215
216/**
217 * Do we need to allocate a pseudo-tty
218 */
219static int need_pty;
220
221/**
222 * Did we set our terminal to raw mode
223 */
224static int tty_rawed;
225
226/**
227 * Destroys a connection context
228 *
229 * @param ctx connection context
230 */
231static void
232destroy_conn_ctx (struct ConnCtx *ctx)
233{
234 struct MessageQueue *mq;
235
236 if (NULL != ctx->tx)
237 {
238 GNUNET_CLIENT_notify_transmit_ready_cancel (ctx->tx);
239 ctx->tx = NULL;
240 }
241 if (NULL != ctx->conn)
242 {
243 GNUNET_CLIENT_disconnect (ctx->conn);
244 ctx->conn = NULL;
245 }
246 if (NULL != ctx->cfg)
247 {
248 GNUNET_CONFIGURATION_destroy (ctx->cfg);
249 ctx->cfg = NULL;
250 }
251 while (NULL != (mq = ctx->mq_head))
252 {
253 GNUNET_CONTAINER_DLL_remove (ctx->mq_head, ctx->mq_tail, mq);
254 GNUNET_free (mq->msg);
255 GNUNET_free (mq);
256 }
257}
258
259
260/**
261 * Shutdown task. Disconnect both client connections by destroying both
262 * contexts
263 *
264 * @param cls NULL
265 * @param tc scheduler task context
266 */
267static void
268do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
269{
270 task_shutdown = GNUNET_SCHEDULER_NO_TASK;
271 LOG_DEBUG ("Shutting down\n");
272 destroy_conn_ctx (&ctx_local);
273 destroy_conn_ctx (&ctx_remote);
274 if ( can_pty && tty_rawed )
275 {
276 if (tcsetattr(0, TCSADRAIN, &tio) == -1)
277 {
278 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "tcsetattr");
279 LOG_ERROR ("Failed to set terminal back from raw mode. "
280 "The terminal may behave wierdly\n");
281 }
282 }
283 if (NULL != fh_stdin)
284 GNUNET_break (GNUNET_OK == GNUNET_DISK_file_close (fh_stdin));
285 if (NULL != fh_stdout)
286 GNUNET_break (GNUNET_OK == GNUNET_DISK_file_close (fh_stdout));
287 if (NULL != fh_stderr)
288 GNUNET_break (GNUNET_OK == GNUNET_DISK_file_close (fh_stderr));
289}
290
291
292/**
293 * Function called to notify a client about the connection
294 * begin ready to queue more data. "buf" will be
295 * NULL and "size" zero if the connection was closed for
296 * writing in the meantime.
297 *
298 * @param cls closure
299 * @param size number of bytes available in buf
300 * @param buf where the callee should write the message
301 * @return number of bytes written to buf
302 */
303static size_t
304conn_transmit_ready (void *cls, size_t size, void *buf)
305{
306 struct ConnCtx *ctx = cls;
307 struct MessageQueue *mq;
308 uint16_t msg_size;
309 size_t wrote;
310
311 wrote = 0;
312 GNUNET_assert (NULL != ctx->tx);
313 ctx->tx = NULL;
314 if ((0 == size) && (NULL == buf))
315 {
316 LOG_ERROR ("Connection to MSHD broken\n");
317 destroy_conn_ctx (ctx);
318 return 0;
319 }
320 mq = ctx->mq_head;
321 GNUNET_assert (NULL != mq);
322 if ((0 == size) || (NULL == buf))
323 {
324 LOG_DEBUG ("Message sending timed out -- retrying\n");
325 ctx->backoff = GNUNET_TIME_STD_BACKOFF (ctx->backoff);
326 ctx->tx =
327 GNUNET_CLIENT_notify_transmit_ready (ctx->conn, ntohs (mq->msg->size),
328 ctx->backoff, GNUNET_NO,
329 &conn_transmit_ready,
330 ctx);
331
332 return 0;
333 }
334 ctx->backoff = GNUNET_TIME_UNIT_ZERO;
335 msg_size = ntohs (mq->msg->size);
336 GNUNET_assert ( msg_size <= size);
337 (void) memcpy (buf, mq->msg, msg_size);
338 wrote = msg_size;
339 LOG_DEBUG ("Message of type %u, size %u sent\n", ntohs (mq->msg->type), ntohs (mq->msg->size));
340 GNUNET_free (mq->msg);
341 GNUNET_CONTAINER_DLL_remove (ctx->mq_head, ctx->mq_tail, mq);
342 GNUNET_free (mq);
343 if (NULL != (mq = ctx->mq_head))
344 {
345 ctx->backoff = GNUNET_TIME_STD_BACKOFF (ctx->backoff);
346 ctx->tx =
347 GNUNET_CLIENT_notify_transmit_ready (ctx->conn, ntohs (mq->msg->size),
348 ctx->backoff, GNUNET_NO,
349 &conn_transmit_ready,
350 ctx);
351 }
352 return wrote;
353}
354
355
356/**
357 * Queues a message in send queue assocaited with conn
358 *
359 * @param msg the message to queue
360 */
361static void
362queue_message (struct ConnCtx *ctx, struct GNUNET_MessageHeader *msg)
363{
364 struct MessageQueue *mq;
365 uint16_t type;
366 uint16_t size;
367
368 type = ntohs (msg->type);
369 size = ntohs (msg->size);
370 mq = GNUNET_malloc (sizeof (struct MessageQueue));
371 mq->msg = msg;
372 LOG_DEBUG ("Queueing message of type %u, size %u for sending\n", type, size);
373 GNUNET_CONTAINER_DLL_insert_tail (ctx->mq_head, ctx->mq_tail, mq);
374 if (NULL == ctx->tx)
375 {
376 ctx->backoff = GNUNET_TIME_STD_BACKOFF (ctx->backoff);
377 ctx->tx =
378 GNUNET_CLIENT_notify_transmit_ready (ctx->conn, size,
379 ctx->backoff, GNUNET_NO,
380 &conn_transmit_ready,
381 ctx);
382 }
383}
384
385
386/**
387 * Dispatcher for received messages
388 *
389 * @param cls connection context
390 * @param msg message received, NULL on timeout or fatal error
391 */
392static void
393dispatch (void *cls, const struct GNUNET_MessageHeader *msg);
394
395
396/**
397 * forward stdin data to MSHD
398 *
399 * @param cls NULL
400 * @param tc scheduler task context
401 */
402static void
403fwd_stdin (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
404{
405 struct MSH_MSG_CmdIO *msg;
406 ssize_t size;
407 uint16_t msg_size;
408
409 task_fwd_stdin = GNUNET_SCHEDULER_NO_TASK;
410 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
411 {
412 return;
413 }
414 size = GNUNET_DISK_file_read (fh_stdin, recv_buf,
415 GNUNET_SERVER_MAX_MESSAGE_SIZE
416 - sizeof (struct MSH_MSG_CmdIO));
417 if (GNUNET_SYSERR == size)
418 {
419 GNUNET_break (0);
420 GNUNET_SCHEDULER_shutdown ();
421 return;
422 }
423 if (0 == size)
424 {
425 GNUNET_SCHEDULER_shutdown ();
426 return;
427 }
428 msg_size = sizeof (struct MSH_MSG_CmdIO) + size;
429 msg = GNUNET_malloc (msg_size);
430 msg->header.size = htons (msg_size);
431 msg->header.type = htons (MSH_MTYPE_CMD_STREAM_STDIN);
432 (void) memcpy (msg->data, recv_buf, size);
433 queue_message (&ctx_remote, &msg->header);
434 task_fwd_stdin =
435 GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
436 fh_stdin, &fwd_stdin, NULL);
437}
438
439
440/**
441 * Type of a function to call when we receive a message
442 * from the service.
443 *
444 * @param ctx the connection context
445 * @param msg message received, NULL on timeout or fatal error
446 * @return GNUNET_OK to keep the connection open; any other value to close it
447 */
448static int
449handle_cmd_output (struct ConnCtx *ctx,
450 const struct GNUNET_MessageHeader *msg_)
451{
452 const struct MSH_MSG_CmdIO *msg;
453 uint16_t size;
454 uint16_t mtype;
455
456 msg = (const struct MSH_MSG_CmdIO *) msg_;
457 mtype = ntohs (msg->header.type);
458 if ( (MSH_MTYPE_CMD_STREAM_STDOUT != mtype)
459 && (MSH_MTYPE_CMD_STREAM_STDERR != mtype) )
460 {
461 GNUNET_break (0);
462 GNUNET_SCHEDULER_shutdown ();
463 return GNUNET_SYSERR;;
464 }
465 size = ntohs (msg->header.size);
466 size -= sizeof (struct MSH_MSG_CmdIO);
467 switch (mtype)
468 {
469 case MSH_MTYPE_CMD_STREAM_STDOUT:
470 GNUNET_break (size == GNUNET_DISK_file_write (fh_stdout, msg->data, size));
471 break;
472 case MSH_MTYPE_CMD_STREAM_STDERR:
473 if (NULL == fh_stderr)
474 break;
475 GNUNET_break (size == GNUNET_DISK_file_write (fh_stderr, msg->data, size));
476 break;
477 default:
478 GNUNET_assert (0);
479 }
480 return GNUNET_OK;
481}
482
483
484/**
485 * Type of a function to call when we receive a message
486 * from the service.
487 *
488 * @param ctx the connection context
489 * @param msg message received, NULL on timeout or fatal error
490 * @return GNUNET_OK to keep the connection open; any other value to close it
491 */
492static int
493handle_exec_begin (struct ConnCtx *ctx,
494 const struct GNUNET_MessageHeader *msg_)
495{
496 LOG (GNUNET_ERROR_TYPE_INFO, "Executing remote command\n");
497 fh_stdin = GNUNET_DISK_get_handle_from_native (stdin);
498 fh_stdout = GNUNET_DISK_get_handle_from_native (stdout);
499 fh_stderr = GNUNET_DISK_get_handle_from_native (stderr);
500 GNUNET_assert (NULL != fh_stdin);
501 GNUNET_assert (NULL != fh_stdout);
502 state = STATE_FORWARD_STREAMS;
503 task_fwd_stdin =
504 GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
505 fh_stdin, &fwd_stdin, NULL);
506 result = GNUNET_OK;
507 return GNUNET_OK;
508}
509
510
511/**
512 * Set the terminal into raw mode
513 */
514void
515enter_raw_mode(int quiet)
516{
517 struct termios raw_tio;
518
519 raw_tio = tio;
520 raw_tio.c_iflag |= IGNPAR;
521 raw_tio.c_iflag &= ~(ISTRIP | INLCR | IGNCR | ICRNL | IXON | IXANY | IXOFF);
522#ifdef IUCLC
523 raw_tio.c_iflag &= ~IUCLC;
524#endif
525 raw_tio.c_lflag &= ~(ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHONL);
526#ifdef IEXTEN
527 raw_tio.c_lflag &= ~IEXTEN;
528#endif
529 raw_tio.c_oflag &= ~OPOST;
530 raw_tio.c_cc[VMIN] = 1;
531 raw_tio.c_cc[VTIME] = 0;
532 if (tcsetattr(fileno(stdin), TCSADRAIN, &raw_tio) == -1) {
533 if (!quiet)
534 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "tcsetattr");
535 } else
536 tty_rawed = 1;
537}
538
539
540/**
541 * Generate PTY_MODE message containing the settings to be used for the created
542 * pseudo-tty
543 *
544 * @return the PTY_MODE message; NULL upon error
545 */
546static struct MSH_MSG_PtyMode *
547gen_pty_msg ()
548{
549 struct MSH_MSG_PtyMode *tmsg;
550 char *cp;
551 uint16_t *ts;
552 size_t size;
553 unsigned int count;
554
555 cp = getenv ("TERM");
556
557 /* count the number of terminal settings */
558 count = 0;
559#define TTYCHAR(NAME,OP) \
560 count++;
561#define TTYMODE(NAME,FIELD,OP) \
562 count++;
563#include "ttymodes.h"
564#undef TTYCHAR
565#undef TTYMODE
566
567 /* Build the terminal mode message */
568 size = sizeof (struct MSH_MSG_PtyMode) +
569 (sizeof (uint16_t) * 2 * count) + ((NULL != cp) ? (strlen(cp) + 1) : 0);
570 tmsg = GNUNET_malloc (size);
571 tmsg->header.type = htons (MSH_MTYPE_PTY_MODE);
572 tmsg->header.size = htons (size);
573 tmsg->ws_row = htons (ws.ws_row);
574 tmsg->ws_col = htons (ws.ws_col);
575 tmsg->ws_xpixel = htons (ws.ws_xpixel);
576 tmsg->ws_ypixel = htons (ws.ws_ypixel);
577 tmsg->ospeed = htonl (speed_to_baud (cfgetospeed (&tio)));
578 tmsg->ispeed = htonl (speed_to_baud (cfgetispeed (&tio)));
579 tmsg->nsettings = htons (count);
580 /* Populate the message with settings */
581 ts = (uint16_t *) &tmsg[1];
582#define TTYCHAR(NAME,OP) \
583 *(ts++) = htons (OP); \
584 *(ts++) = htons (tio.c_cc[NAME]);
585
586#define TTYMODE(NAME, FIELD, OP) \
587 *(ts++) = htons (OP); \
588 *(ts++) = htons ((tio.FIELD & NAME) != 0);
589#include "ttymodes.h"
590#undef TTYCHAR
591#undef TTYMODE
592 /* copy the TERM env variable's value */
593 if (NULL != cp)
594 (void) memcpy ((void *)ts, cp, strlen (cp));
595 return tmsg;
596}
597
598
599/**
600 * Type of a function to call when we receive a message
601 * from the service.
602 *
603 * @param ctx the connection context
604 * @param msg message received, NULL on timeout or fatal error
605 * @return GNUNET_OK to keep the connection open; any other value to close it
606 */
607static int
608handle_challenge_response (struct ConnCtx *ctx,
609 const struct GNUNET_MessageHeader *msg_)
610{
611 struct GNUNET_MessageHeader *msg;
612 struct MSH_MSG_RunCmd *rmsg;
613 struct MSH_MSG_PtyMode *ptymsg;
614 uint16_t size;
615
616 LOG_DEBUG ("Received CHALLENGE_RESPONSE. Forwarding it to remote MSHD\n");
617 msg = GNUNET_copy_message (msg_);
618 queue_message (&ctx_remote, msg);
619 destroy_conn_ctx (&ctx_local);
620 if (can_pty && !disable_pty)
621 {
622 ptymsg = gen_pty_msg ();
623 queue_message (&ctx_remote, &ptymsg->header);
624 enter_raw_mode (1);
625 }
626 /* now queue RUN_CMD message */
627 size = sizeof (struct MSH_MSG_RunCmd) + cmdstr_len;
628 rmsg = GNUNET_malloc (size);
629 rmsg->header.size = htons (size);
630 rmsg->header.type = htons (MSH_MTYPE_RUNCMD);
631 (void) memcpy (rmsg->cmd, cmdstr, cmdstr_len);
632 queue_message (&ctx_remote, &rmsg->header);
633 return GNUNET_OK;
634}
635
636
637/**
638 * Type of a function to call when we receive a message
639 * from the service.
640 *
641 * @param ctx the connection context
642 * @param msg message received, NULL on timeout or fatal error
643 * @return GNUNET_OK to keep the connection open; any other value to close it
644 */
645static int
646handle_challenge (struct ConnCtx *ctx,
647 const struct GNUNET_MessageHeader *msg_)
648{
649 struct GNUNET_MessageHeader *msg;
650
651 LOG_DEBUG ("Received CHALLENGE message. Forwarding it to parent MSHD\n");
652 if (sizeof (struct MSH_MSG_Challenge) > ntohs (msg_->size))
653 {
654 GNUNET_break (0);
655 return GNUNET_SYSERR;
656 }
657 msg = GNUNET_copy_message (msg_);
658 queue_message (&ctx_local, msg);
659 return GNUNET_OK;
660}
661
662
663/**
664 * Tries to establish a connection to the target remote MSHD
665 */
666static void
667target_connect ()
668{
669 struct MSH_MSG_SessionOpen *msg;
670 struct GNUNET_CONFIGURATION_Handle *cfg;
671 uint16_t size;
672
673 cfg = GNUNET_CONFIGURATION_create ();
674 GNUNET_CONFIGURATION_set_value_string (cfg, MSHD_REMOTE, "HOSTNAME",
675 ip2str (target));
676 GNUNET_CONFIGURATION_set_value_number (cfg, MSHD_REMOTE, "PORT",
677 target_port);
678 ctx_remote.cfg = cfg;
679 ctx_remote.conn = GNUNET_CLIENT_connect (MSHD_REMOTE, ctx_remote.cfg);
680 GNUNET_assert (NULL != ctx_remote.conn);
681 size = sizeof (struct MSH_MSG_SessionOpen);
682 msg = GNUNET_malloc (size);
683 msg->header.size = htons (size);
684 msg->header.type = htons (MSH_MTYPE_SESSION_OPEN);
685 //(void) memcpy (msg->cmd, cmdstr, cmdstr_len);
686 if (can_pty)
687 msg->type = htonl (MSH_SESSION_TYPE_INTERACTIVE);
688 else
689 msg->type = htonl (MSH_SESSION_TYPE_NONINTERACTIVE);
690 queue_message (&ctx_remote, &msg->header);
691 GNUNET_CLIENT_receive (ctx_remote.conn, &dispatch, &ctx_remote,
692 GNUNET_TIME_UNIT_FOREVER_REL);
693 }
694
695
696/**
697 * Type of a function to call when we receive a message
698 * from the service.
699 *
700 * @param ctx the connection context
701 * @param msg message received, NULL on timeout or fatal error
702 * @return GNUNET_OK to keep the connection open; any other value to close it
703 */
704static int
705handle_lookup_reply (struct ConnCtx *ctx,
706 const struct GNUNET_MessageHeader *msg_)
707{
708 const struct MSH_MSG_AddressLookupReply *msg;
709 uint16_t size;
710
711 size = ntohs (msg_->size);
712 msg = (const struct MSH_MSG_AddressLookupReply *) msg_;
713 if (0 == (target_port = ntohs (msg->port)))
714 {
715 if ('\0' != msg->emsg[(size - sizeof (struct MSH_MSG_AddressLookup)) - 1])
716 {
717 GNUNET_break (0);
718 return GNUNET_SYSERR;
719 }
720 LOG_ERROR ("Address lookup for IP:%s failed with error: %s\n",
721 ip2str (target), msg->emsg);
722 return GNUNET_SYSERR;
723 }
724 LOG_DEBUG ("ADDRESS_LOOKUP_REPLY: Service available on %s:%u\n",
725 ip2str (target), target_port);
726 target_connect ();
727 return GNUNET_OK;
728}
729
730
731/**
732 * Dispatcher for received messages
733 *
734 * @param cls connection context
735 * @param msg message received, NULL on timeout or fatal error
736 */
737static void
738dispatch (void *cls, const struct GNUNET_MessageHeader *msg)
739{
740 struct ConnCtx *ctx = cls;
741 int ret;
742
743 if (NULL == msg)
744 {
745 LOG_DEBUG ("Broken IPC connection\n");
746 goto err_ret;
747 }
748 switch (ntohs (msg->type))
749 {
750 case MSH_MTYPE_ADDRESS_LOOKUP_REPLY:
751 ret = handle_lookup_reply (ctx, msg);
752 break;
753 case MSH_MTYPE_CHALLENGE:
754 ret = handle_challenge (ctx, msg);
755 break;
756 case MSH_MTYPE_CHALLENGE_RESPONSE:
757 ret = handle_challenge_response (ctx, msg);
758 break;
759 case MSH_MTYPE_EXEC_BEGIN:
760 ret = handle_exec_begin (ctx, msg);
761 break;
762 case MSH_MTYPE_CMD_STREAM_STDOUT:
763 case MSH_MTYPE_CMD_STREAM_STDERR:
764 ret = handle_cmd_output (ctx, msg);
765 break;
766 default:
767 LOG (GNUNET_ERROR_TYPE_WARNING, "Unrecognised message of type %u received\n",
768 ntohs (msg->type));
769 goto err_ret;
770 }
771 if (GNUNET_SYSERR == ret)
772 goto err_ret;
773
774 /* We destroy local_ctx in handle_challenge_response, hence this check */
775 if (NULL != ctx->conn)
776 GNUNET_CLIENT_receive (ctx->conn, &dispatch, ctx, GNUNET_TIME_UNIT_FOREVER_REL);
777 return;
778
779 err_ret:
780 destroy_conn_ctx (ctx);
781 GNUNET_SCHEDULER_shutdown ();
782}
783
784
785/**
786 * Function called with the result on the service test.
787 *
788 * @param cls NULL
789 * @param status GNUNET_YES if the service is running,
790 * GNUNET_NO if the service is not running
791 * GNUNET_SYSERR if the configuration is invalid
792 */
793static void
794status_cb (void *cls, int status)
795{
796 struct MSH_MSG_AddressLookup *msg;
797 uint16_t size;
798
799 test = NULL;
800 if (GNUNET_YES != status)
801 {
802 LOG_ERROR ("Service not running\n");
803 return;
804 }
805 ctx_local.conn = GNUNET_CLIENT_connect (MSHD_LOCAL, ctx_local.cfg);
806 GNUNET_assert (NULL != ctx_local.conn);
807 GNUNET_assert (0 != cmdstr_len);
808 size = sizeof (struct MSH_MSG_AddressLookup);
809 msg = GNUNET_malloc (size);
810 msg->header.size = htons (size);
811 msg->header.type = htons (MSH_MTYPE_ADDRESS_LOOKUP);
812 msg->ip = htonl ((uint32_t) target);
813 queue_message (&ctx_local, &msg->header);
814 GNUNET_CLIENT_receive (ctx_local.conn, &dispatch, &ctx_local,
815 GNUNET_TIME_UNIT_FOREVER_REL);
816 task_shutdown = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
817 &do_shutdown, NULL);
818}
819
820
821/**
822 * Reads terminal settings and window size
823 *
824 * @return GNUNET_OK upon success; GNUNET_SYSERR upon error
825 */
826static int
827read_tty_settings ()
828{
829 if (ioctl(0, TIOCGWINSZ, &ws) < 0)
830 {
831 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "ioctl");
832 return GNUNET_SYSERR;
833 }
834 if (-1 == tcgetattr (0, &tio))
835 {
836 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "tcgetattr");
837 return GNUNET_SYSERR;
838 }
839 return GNUNET_OK;
840}
841
842
843/**
844 * Main function that will be run.
845 *
846 * @param cls closure
847 * @param args remaining command-line arguments
848 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
849 * @param cfg_ configuration
850 */
851static void
852run (void *cls, char *const *args, const char *cfgfile,
853 const struct GNUNET_CONFIGURATION_Handle *cfg_)
854{
855 char *ipstr;
856 char *psock_path;
857 size_t arg_len;
858 unsigned int cnt;
859
860 if (!disable_pty && isatty (0))
861 can_pty = 1;
862 if (need_pty && !can_pty)
863 {
864 LOG_ERROR ("Not attached to a terminal but pseudo-tty is requested (-t) option");
865 return;
866 }
867 if (can_pty)
868 {
869 if (GNUNET_OK != read_tty_settings ())
870 return;
871 }
872 state = STATE_DELIVER_CMD;
873 if (NULL == (ipstr = args[0]))
874 {
875 LOG_ERROR ("Require an IP address\n");
876 fprintf (stderr, "%s", help_text);
877 return;
878 }
879 target = inet_network (ipstr);
880 if ((uint32_t) -1 == target)
881 {
882 LOG_ERROR ("Invalid IP address given");
883 return;
884 }
885 for (cnt = 1; NULL != args[cnt]; cnt++)
886 {
887 arg_len = strlen (args[cnt]) + 1;
888 cmdstr = GNUNET_realloc (cmdstr, cmdstr_len + arg_len);
889 (void) memcpy (cmdstr + cmdstr_len, args[cnt], arg_len);
890 cmdstr_len += arg_len;
891 }
892 if (0 == cmdstr_len)
893 {
894 LOG_ERROR ("Require command to execute remotely\n");
895 fprintf (stderr, "%s", help_text);
896 return;
897 }
898 if (NULL == (psock_path = getenv("MSHD_SOCK")) )
899 {
900 LOG_ERROR ("Could not find socket for local MSHD. Are we running under MSHD?\n");
901 return;
902 }
903 LOG_DEBUG ("Unix socket path: %s\n", psock_path);
904 ctx_local.cfg = GNUNET_CONFIGURATION_dup (cfg_);
905 GNUNET_CONFIGURATION_set_value_string (ctx_local.cfg, MSHD_LOCAL,
906 "UNIXPATH", psock_path);
907 GNUNET_CONFIGURATION_set_value_string (ctx_local.cfg, "TESTING",
908 "USE_ABSTRACT_SOCKETS", "YES");
909 test = GNUNET_CLIENT_service_test (MSHD_LOCAL, ctx_local.cfg,
910 GNUNET_TIME_UNIT_SECONDS,
911 &status_cb, NULL);
912}
913
914
915/**
916 * Program entry point
917 */
918int
919main (int argc, char * const argv[])
920{
921 static const struct GNUNET_GETOPT_CommandLineOption options[] = {
922 {'T', "disable-pty", NULL, _("do not allocate a pseudo-tty"), 0,
923 &GNUNET_GETOPT_set_one, (void *) &disable_pty},
924 {'t', "require-pty", NULL, _("exit with error if a pseudo-tty cannot be allocated"),
925 0, &GNUNET_GETOPT_set_one, (void *) &need_pty},
926 GNUNET_GETOPT_OPTION_END
927 };
928
929 result = GNUNET_SYSERR;
930 if (GNUNET_OK != GNUNET_PROGRAM_run (argc, argv, "msh",
931 help_text,
932 options, &run, NULL))
933 {
934 GNUNET_break (0);
935 return 1;
936 }
937 return (GNUNET_OK == result) ? 0 : 2;
938}
diff --git a/src/msh_waiter.c b/src/msh_waiter.c
new file mode 100644
index 0000000..69bb909
--- /dev/null
+++ b/src/msh_waiter.c
@@ -0,0 +1,392 @@
1#include "common.h"
2#include <gnunet/gnunet_util_lib.h>
3#include "mtypes.h"
4#include <termios.h>
5
6#define LOG(kind,...) \
7 GNUNET_log (kind, __VA_ARGS__)
8
9#define LOG_DEBUG(...) LOG(GNUNET_ERROR_TYPE_DEBUG, __VA_ARGS__)
10
11#define LOG_ERROR(...) LOG(GNUNET_ERROR_TYPE_ERROR, __VA_ARGS__)
12
13#define TIMEOUT(secs) \
14 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, secs)
15
16#define DEFAULT_TIMEOUT TIMEOUT(30)
17
18#define PROG_NAME "msh-waiter"
19
20static unsigned int port;
21
22static struct GNUNET_CONFIGURATION_Handle *cfg;
23
24static struct GNUNET_NETWORK_Handle *lsock;
25
26static struct GNUNET_CONNECTION_Handle *conn;
27
28static struct GNUNET_MessageHeader *msg;
29
30static struct GNUNET_CONNECTION_TransmitHandle *handle_tx;
31
32static struct GNUNET_DISK_FileHandle *fh_stdin;
33
34static struct termios saved_tio;
35
36static int in_raw_mode;
37
38static int in_receive;
39
40#define BUF_SIZE 512
41static char in_buf[BUF_SIZE];
42
43static ssize_t size_in_buf;
44
45static void
46do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
47{
48 if (NULL != handle_tx)
49 GNUNET_CONNECTION_notify_transmit_ready_cancel (handle_tx);
50 if (NULL != conn)
51 {
52 if (in_receive)
53 GNUNET_CONNECTION_receive_cancel (conn);
54 GNUNET_CONNECTION_destroy (conn);
55 }
56 if (NULL != lsock)
57 GNUNET_NETWORK_socket_close (lsock);
58 if (NULL != cfg)
59 GNUNET_CONFIGURATION_destroy (cfg);
60 GNUNET_free_non_null (msg);
61 if (!in_raw_mode)
62 return;
63 if (tcsetattr(fileno(stdin), TCSADRAIN, &saved_tio) == -1)
64 {
65 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "tcsetattr");
66 LOG_ERROR ("Failed to set terminal back from raw mode. "
67 "The terminal may behave wierdly\n");
68 }
69 if (NULL != fh_stdin)
70 GNUNET_DISK_file_close (fh_stdin);
71}
72
73
74/**
75 * Set the terminal into raw mode
76 */
77void
78enter_raw_mode(int quiet)
79{
80 struct termios tio;
81
82 if (tcgetattr(fileno(stdin), &tio) == -1) {
83 if (!quiet)
84 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "tcgetattr");
85 return;
86 }
87 saved_tio = tio;
88 tio.c_iflag |= IGNPAR;
89 tio.c_iflag &= ~(ISTRIP | INLCR | IGNCR | ICRNL | IXON | IXANY | IXOFF);
90#ifdef IUCLC
91 tio.c_iflag &= ~IUCLC;
92#endif
93 tio.c_lflag &= ~(ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHONL);
94#ifdef IEXTEN
95 tio.c_lflag &= ~IEXTEN;
96#endif
97 tio.c_oflag &= ~OPOST;
98 tio.c_cc[VMIN] = 1;
99 tio.c_cc[VTIME] = 0;
100 if (tcsetattr(fileno(stdin), TCSADRAIN, &tio) == -1) {
101 if (!quiet)
102 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "tcsetattr");
103 } else
104 in_raw_mode = 1;
105}
106
107
108/**
109 * Callback function for data received from the network. Note that
110 * both "available" and "err" would be 0 if the read simply timed out.
111 *
112 * @param cls closure
113 * @param buf pointer to received data
114 * @param available number of bytes availabe in "buf",
115 * possibly 0 (on errors)
116 * @param addr address of the sender
117 * @param addrlen size of addr
118 * @param errCode value of errno (on errors receiving)
119 */
120static void
121receive (void *cls, const void *buf, size_t available,
122 const struct sockaddr * addr, socklen_t addrlen, int errCode)
123{
124 in_receive = GNUNET_NO;
125 if (0 == available)
126 goto err_ret;
127 if (available != fwrite (buf, 1, available, stdout))
128 {
129 LOG_ERROR ("Error writing to stdout\n");
130 goto err_ret;
131 }
132 if (0 != fflush (stdout))
133 {
134 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "fflush");
135 goto err_ret;
136 }
137 GNUNET_CONNECTION_receive (conn, GNUNET_SERVER_MAX_MESSAGE_SIZE,
138 GNUNET_TIME_UNIT_FOREVER_REL, &receive, NULL);
139 return;
140
141 err_ret:
142 GNUNET_SCHEDULER_shutdown ();
143}
144
145
146/**
147 * Task to read from stdin
148 */
149static void
150read_stdin (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
151
152
153/**
154 * Transmit the global msg
155 *
156 * @param cls closure
157 * @param size number of bytes available in buf
158 * @param buf where the callee should write the message
159 * @return number of bytes written to buf
160 */
161static size_t
162tx_stdin (void *cls, size_t size, void *buf)
163{
164 handle_tx = NULL;
165 if ((NULL == buf) || (0 == size))
166 {
167 LOG_ERROR ("Failure in connectivity\n");
168 GNUNET_SCHEDULER_shutdown ();
169 return 0;
170 }
171 GNUNET_assert (size_in_buf <= size);
172 (void) memcpy (buf, in_buf, size_in_buf);
173 GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, fh_stdin,
174 &read_stdin, NULL);
175 return size_in_buf;
176}
177
178
179/**
180 * Task to read from stdin
181 */
182static void
183read_stdin (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
184{
185 if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_READ_READY))
186 return;
187 size_in_buf = GNUNET_DISK_file_read (fh_stdin, in_buf, BUF_SIZE);
188 if (GNUNET_SYSERR == size_in_buf)
189 {
190 LOG_ERROR ("Read error\n");
191 GNUNET_SCHEDULER_shutdown ();
192 return;
193 }
194 handle_tx = GNUNET_CONNECTION_notify_transmit_ready (conn, size_in_buf,
195 DEFAULT_TIMEOUT,
196 &tx_stdin, NULL);
197}
198
199
200/**
201 * Transmit the global msg
202 *
203 * @param cls closure
204 * @param size number of bytes available in buf
205 * @param buf where the callee should write the message
206 * @return number of bytes written to buf
207 */
208static size_t
209tx_pty_mode (void *cls, size_t size, void *buf)
210{
211 size_t nb;
212
213 handle_tx = NULL;
214 if ((NULL == buf) || (0 == size))
215 {
216 LOG_ERROR ("Failure in connectivity\n");
217 GNUNET_SCHEDULER_shutdown ();
218 return 0;
219 }
220 GNUNET_assert (NULL != msg);
221 nb = ntohs (msg->size);
222 GNUNET_assert (nb <= size);
223 (void) memcpy (buf, msg, nb);
224 GNUNET_free (msg);
225 msg = NULL;
226 GNUNET_CONNECTION_receive (conn, GNUNET_SERVER_MAX_MESSAGE_SIZE,
227 GNUNET_TIME_UNIT_FOREVER_REL, &receive, NULL);
228 in_receive = GNUNET_YES;
229 fh_stdin = GNUNET_DISK_get_handle_from_native (stdin);
230 GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, fh_stdin,
231 &read_stdin, NULL);
232 return nb;
233}
234
235
236/**
237 * Accept a connection on listen socket
238 */
239static void
240accept_lsock (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
241{
242 struct termios tio;
243 struct winsize ws;
244 struct MSH_MSG_PtyMode *tmsg;
245 char *cp;
246 uint16_t *ts;
247 size_t size;
248 unsigned int count;
249
250 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
251 return;
252 conn = GNUNET_CONNECTION_create_from_accept (NULL, NULL, lsock);
253 GNUNET_NETWORK_socket_close (lsock);
254 lsock = NULL;
255 if (NULL == conn)
256 {
257 LOG_ERROR ("Failed to create incoming connection");
258 GNUNET_SCHEDULER_shutdown ();
259 return;
260 }
261 if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) < 0)
262 memset(&ws, 0, sizeof(ws));
263 cp = getenv ("TERM");
264 /* count terminal settings */
265 count = 0;
266
267#define TTYCHAR(NAME,OP) \
268 count++;
269#define TTYMODE(NAME,FIELD,OP) \
270 count++;
271#include "ttymodes.h"
272#undef TTYCHAR
273#undef TTYMODE
274
275 size = sizeof (struct MSH_MSG_PtyMode) +
276 (sizeof (uint16_t) * 2 * count) + ((NULL != cp) ? (strlen(cp) + 1) : 0);
277 if (-1 == tcgetattr (0, &tio))
278 {
279 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "tcgetattr");
280 GNUNET_SCHEDULER_shutdown ();
281 return;
282 }
283 tmsg = GNUNET_malloc (size);
284 tmsg->header.type = htons (MSH_MTYPE_PTY_MODE);
285 tmsg->header.size = htons (size);
286 tmsg->ws_row = htons (ws.ws_row);
287 tmsg->ws_col = htons (ws.ws_col);
288 tmsg->ws_xpixel = htons (ws.ws_xpixel);
289 tmsg->ws_ypixel = htons (ws.ws_ypixel);
290 tmsg->ospeed = htonl (speed_to_baud (cfgetospeed (&tio)));
291 tmsg->ispeed = htonl (speed_to_baud (cfgetispeed (&tio)));
292 tmsg->nsettings = htons (count);
293
294 ts = (uint16_t *) &tmsg[1];
295#define TTYCHAR(NAME,OP) \
296 *(ts++) = htons (OP); \
297 *(ts++) = htons (tio.c_cc[NAME]);
298
299#define TTYMODE(NAME, FIELD, OP) \
300 *(ts++) = htons (OP); \
301 *(ts++) = htons ((tio.FIELD & NAME) != 0);
302#include "ttymodes.h"
303#undef TTYCHAR
304#undef TTYMODE
305
306 if (NULL != cp)
307 (void) memcpy ((void *)ts, cp, strlen (cp));
308 enter_raw_mode (1);
309 msg = &tmsg->header;
310 handle_tx = GNUNET_CONNECTION_notify_transmit_ready (conn, size, DEFAULT_TIMEOUT,
311 &tx_pty_mode, NULL);
312 if (NULL == handle_tx)
313 {
314 LOG_ERROR ("Failed to transmit PTY mode\n");
315 GNUNET_SCHEDULER_shutdown ();
316 return;
317 }
318}
319
320
321/**
322 * Main function that will be run by the scheduler.
323 *
324 * @param cls closure
325 * @param args remaining command-line arguments
326 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
327 * @param c configuration
328 */
329static void
330run (void *cls,
331 char *const *args,
332 const char *cfgfile,
333 const struct GNUNET_CONFIGURATION_Handle *c)
334{
335 struct sockaddr_in laddr;
336 int ret;
337
338 cfg = GNUNET_CONFIGURATION_dup (c);
339 lsock = GNUNET_NETWORK_socket_create (AF_INET, SOCK_STREAM, 0);
340 memset (&laddr, 0, sizeof (laddr));
341 laddr.sin_addr.s_addr = INADDR_ANY;
342 laddr.sin_port = htons (port);
343 ret = GNUNET_NETWORK_socket_bind (lsock, (const struct sockaddr *) &laddr,
344 sizeof (laddr));
345 if (GNUNET_SYSERR == ret)
346 goto err_ret;
347 ret = GNUNET_NETWORK_socket_listen (lsock, 1);
348 if (GNUNET_SYSERR == ret)
349 goto err_ret;
350
351 GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
352 lsock, &accept_lsock, NULL);
353 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
354 &do_shutdown, NULL);
355 return;
356
357 err_ret:
358 GNUNET_NETWORK_socket_close (lsock);
359 GNUNET_CONFIGURATION_destroy (cfg);
360 return;
361}
362
363
364int main (int argc, char * const *argv)
365{
366 static const struct GNUNET_GETOPT_CommandLineOption options[] = {
367 {'p', "port", NULL, gettext_noop ("listen port"),
368 GNUNET_YES, &GNUNET_GETOPT_set_uint, &port},
369 GNUNET_GETOPT_OPTION_END
370 };
371 int ret;
372
373 if (!isatty(0))
374 {
375 fprintf (stderr, "Not running with a tty. Exiting\n");
376 return 1;
377 }
378 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
379 return 2;
380 if (GNUNET_OK != (ret =
381 GNUNET_PROGRAM_run (argc, argv, PROG_NAME,
382 gettext_noop
383 ("waiter program for providing TTY supported "
384 "interaction with the master process spawned from MSHD"),
385 options, &run, NULL)))
386 {
387 GNUNET_free ((void *) argv);
388 return ret;
389 }
390 GNUNET_free ((void *) argv);
391 return ret;
392}
diff --git a/src/mshd.c b/src/mshd.c
new file mode 100644
index 0000000..0549052
--- /dev/null
+++ b/src/mshd.c
@@ -0,0 +1,1550 @@
1/**
2 * @file mshd.c
3 * @brief implementation of the MSH Daemon
4 * @author Sree Harsha Totakura <sreeharsha@totakura.in>
5 */
6
7#include "common.h"
8#include <gnunet/gnunet_util_lib.h>
9#include <mpi.h>
10#include "util.h"
11#include "mtypes.h"
12#include "bitmap.h"
13#include "addressmap.h"
14#include "reduce.h"
15#include "pmonitor.h"
16#include "server.h"
17
18#include <sys/resource.h>
19
20#define LOG(kind,...) \
21 GNUNET_log (kind, __VA_ARGS__)
22
23#define LOG_DEBUG(...) LOG(GNUNET_ERROR_TYPE_DEBUG, __VA_ARGS__)
24
25#define LOG_ERROR(...) LOG(GNUNET_ERROR_TYPE_ERROR, __VA_ARGS__)
26
27#define LOG_STRERROR(kind,cmd) \
28 GNUNET_log_from_strerror (kind, "mshd", cmd)
29
30/**
31 * Polling interval for checking termination signal
32 */
33#define POLL_SHUTDOWN_INTERVAL \
34 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 500)
35
36/**
37 * Context for verifying addresses
38 */
39struct VerifyAddressesCtx
40{
41 /**
42 * The DLL next ptr
43 */
44 struct VerifyAddressesCtx *next;
45
46 /**
47 * The DLL prev ptr
48 */
49 struct VerifyAddressesCtx *prev;
50
51 /**
52 * The instance addresses
53 */
54 struct InstanceAddrInfo *iainfo;
55
56 /**
57 * The connection handle to the received instance address
58 */
59 struct GNUNET_CONNECTION_Handle *conn;
60
61 /**
62 * The transmit handle for the above connection
63 */
64 struct GNUNET_CONNECTION_TransmitHandle *transmit_handle;
65
66 /**
67 * task to close the connection
68 */
69 GNUNET_SCHEDULER_TaskIdentifier close_task;
70
71 /**
72 * state for the context
73 */
74 enum {
75 VERIFY_ADDRESS_CTX_WRITE,
76
77 VERIFY_ADDRESS_CTX_CLOSE
78 } state;
79
80 /**
81 * the ip address
82 */
83 in_addr_t ip;
84
85 /**
86 * the port number
87 */
88 uint16_t port;
89
90};
91
92
93/**
94 * Context information for reading from incoming connections
95 */
96struct ReadContext
97{
98 /**
99 * next pointer for DLL
100 */
101 struct ReadContext *next;
102
103 /**
104 * prev pointer for DLL
105 */
106 struct ReadContext *prev;
107
108 /**
109 * The connection
110 */
111 struct GNUNET_CONNECTION_Handle *conn;
112
113 /**
114 * are we waiting for a read on the above connection
115 */
116 int in_receive;
117};
118
119
120/**
121 * The mode of the current listen socket;
122 */
123enum ListenMode
124{
125 /**
126 * Mode in which the listen socket accepts connections from other instances
127 * and closes them immediately after reading some data. The incoming
128 * connections are used to verify which IP addresses of this instance are
129 * reachable from other instances
130 */
131 MODE_PROBE,
132
133 /**
134 * In this mode the listen socket accepts requests for starting remote processes
135 */
136 MODE_SERV,
137
138 /**
139 * In this mode we only server address lookups via UNIX domain sockets
140 */
141 MODE_LOCAL_SERV,
142
143 /**
144 * Worker mode
145 */
146 MODE_WORKER
147
148} mode;
149
150
151/**
152 * Context information for the child processes we start
153 */
154struct ChildProc
155{
156 /**
157 * DLL next
158 */
159 struct ChildProc *next;
160
161 /**
162 * DLL prev
163 */
164 struct ChildProc *prev;
165
166 /**
167 * Singalling pipe's write end
168 */
169 struct GNUNET_DISK_FileHandle *sig_write;
170
171 /**
172 * The process id of the child process
173 */
174 pid_t pid;
175};
176
177
178/**
179 * Mapping for instance addresses
180 */
181AddressMap *addrmap;
182
183/**
184 * Reverse mapping of the address map
185 */
186struct ReverseAddressMap *rmap;
187
188/**
189 * Rank of this process
190 */
191int rank;
192
193/**
194 * Given width of the round -- how many other mshd instances verify our IP
195 * addresses in a round
196 */
197unsigned int round_width;
198
199/**
200 * The actual width of the current round. This should be less than or equal to
201 * round_width
202 */
203unsigned int current_round_width;
204
205/**
206 * The number of total mshd processes
207 */
208int nproc;
209
210
211/****************************/
212/* static variables */
213/****************************/
214
215/**
216 * DLL head for the child process contexts
217 */
218static struct ChildProc *chld_head;
219
220/**
221 * DLL tail for the child process contexts
222 */
223static struct ChildProc *chld_tail;
224
225/**
226 * DLL head for address verification contexts
227 */
228static struct VerifyAddressesCtx *vactx_head;
229
230/**
231 * DLL tail for address verification contexts
232 */
233static struct VerifyAddressesCtx *vactx_tail;
234
235/**
236 * Array of our IP addresses in network-byte format
237 */
238static in_addr_t *s_addrs;
239
240/**
241 * network handle for the listen socket
242 */
243static struct GNUNET_NETWORK_Handle *listen_socket;
244
245/**
246 * The process handle of the process started by instance running with rank 0
247 */
248static struct GNUNET_OS_Process *proc;
249
250/**
251 * Task for running a round
252 */
253static GNUNET_SCHEDULER_TaskIdentifier rtask;
254
255/**
256 * Task for asynchronous accept on the socket
257 */
258static GNUNET_SCHEDULER_TaskIdentifier accept_task;
259
260/**
261 * Task for finalising a round
262 */
263static GNUNET_SCHEDULER_TaskIdentifier finalise_task;
264
265/**
266 * Bitmap for checking which MPI processes have verified our addresses in the
267 * current round
268 */
269static struct BitMap *bitmap;
270
271/**
272 * Instances addresses learnt in the current round
273 */
274struct InstanceAddrInfo **riainfos;
275
276/**
277 * head for read context DLL
278 */
279static struct ReadContext *rhead;
280
281/**
282 * tail for read context DLL
283 */
284static struct ReadContext *rtail;
285
286/**
287 * arguments representing the command to run and its arguments
288 */
289static char **run_args;
290
291/**
292 * The path of the unix domain socket we use for communication with local MSH clients
293 */
294static char *unixpath;
295
296/**
297 * The file where the addresses of available hosts are written to
298 */
299static char *hostsfile;
300
301/**
302 * shutdown task
303 */
304GNUNET_SCHEDULER_TaskIdentifier shutdown_task;
305
306/**
307 * Shutdown polling task
308 */
309GNUNET_SCHEDULER_TaskIdentifier poll_shutdown_task;
310
311/**
312 * Random hashcode for authentication
313 */
314struct GNUNET_HashCode shash;
315
316/**
317 * Number of IP addresses
318 */
319static unsigned int nips;
320
321/**
322 * Current IP verification round
323 */
324static unsigned int current_round;
325
326/**
327 * Total number of rounds required
328 */
329static unsigned int total_rounds;
330
331/**
332 * The port number of our local socket
333 */
334uint16_t listen_port;
335
336/******************************************************************/
337/* Static variables to be used only in the local worker processes */
338/******************************************************************/
339
340/**
341 * The signalling pipe's read end
342 */
343struct GNUNET_DISK_FileHandle *worker_sigfd;
344
345/**
346 * Function to copy NULL terminated list of arguments
347 *
348 * @param argv the NULL terminated list of arguments. Cannot be NULL.
349 * @return the copied NULL terminated arguments
350 */
351static char **
352copy_argv (char *const *argv)
353{
354 char **argv_dup;
355 unsigned int argp;
356
357 GNUNET_assert (NULL != argv);
358 for (argp = 0; NULL != argv[argp]; argp++) ;
359 argv_dup = GNUNET_malloc (sizeof (char *) * (argp + 1));
360 for (argp = 0; NULL != argv[argp]; argp++)
361 argv_dup[argp] = strdup (argv[argp]);
362 return argv_dup;
363}
364
365
366/**
367 * Frees the given NULL terminated arguments
368 *
369 * @param argv the NULL terminated list of arguments
370 */
371static void
372free_argv (char **argv)
373{
374 unsigned int argp;
375
376 for (argp = 0; NULL != argv[argp]; argp++)
377 GNUNET_free (argv[argp]);
378 GNUNET_free (argv);
379}
380
381
382/**
383 * Perform cleanup for shutdown
384 *
385 * @param cls NULL
386 * @param tc scheduler task context
387 */
388static void
389do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
390{
391 struct ChildProc *chld;
392 int sig;
393
394 shutdown_task = GNUNET_SCHEDULER_NO_TASK;
395 switch (mode)
396 {
397 case MODE_PROBE:
398 break;
399 case MODE_SERV:
400 if (NULL != (chld = chld_head))
401 {
402 LOG_DEBUG ("Delaying shutdown\n");
403 shutdown_task = GNUNET_SCHEDULER_add_delayed
404 (GNUNET_TIME_UNIT_FOREVER_REL, &do_shutdown, NULL);
405 sig = GNUNET_TERM_SIG;
406 while (NULL != chld)
407 {
408 GNUNET_break (0 == kill (chld->pid, sig));
409 if (NULL != chld->sig_write)
410 GNUNET_break (0 < GNUNET_DISK_file_write (chld->sig_write, &sig, sizeof (int)));
411 chld = chld->next;
412 }
413 return;
414 }
415 MSH_pmonitor_shutdown ();
416 break;
417 case MODE_LOCAL_SERV:
418 shutdown_local_server ();
419 if (0 == rank)
420 MSH_pmonitor_shutdown ();
421 break;
422 case MODE_WORKER:
423 shutdown_daemon_server ();
424 MSH_pmonitor_shutdown ();
425 break;
426 }
427 if (GNUNET_SCHEDULER_NO_TASK != accept_task)
428 {
429 GNUNET_SCHEDULER_cancel (accept_task);
430 accept_task = GNUNET_SCHEDULER_NO_TASK;
431 }
432 if (NULL != listen_socket)
433 {
434 GNUNET_NETWORK_socket_close (listen_socket);
435 listen_socket = NULL;
436 }
437 if (NULL != bitmap)
438 {
439 bitmap_destroy (bitmap);
440 bitmap = NULL;
441 }
442 if (NULL != addrmap)
443 {
444 addressmap_destroy (addrmap);
445 addrmap = NULL;
446 }
447 if (NULL != rmap)
448 {
449 reverse_map_destroy (rmap);
450 rmap = NULL;
451 }
452 GNUNET_free_non_null (s_addrs);
453 s_addrs = NULL;
454 if (NULL != run_args)
455 {
456 free_argv (run_args);
457 run_args = NULL;
458 }
459 GNUNET_free_non_null (unixpath);
460 unixpath = NULL;
461 if (NULL != hostsfile)
462 {
463 (void) unlink (hostsfile);
464 GNUNET_free (hostsfile);
465 hostsfile = NULL;
466 }
467}
468
469
470/**
471 * Callback function invoked for each interface found.
472 *
473 * @param cls closure
474 * @param name name of the interface (can be NULL for unknown)
475 * @param isDefault is this presumably the default interface
476 * @param addr address of this interface (can be NULL for unknown or unassigned)
477 * @param broadcast_addr the broadcast address (can be NULL for unknown or unassigned)
478 * @param netmask the network mask (can be NULL for unknown or unassigned))
479 * @param addrlen length of the address
480 * @return GNUNET_OK to continue iteration, GNUNET_SYSERR to abort
481 */
482static int net_if_processor (void *cls, const char *name,
483 int isDefault,
484 const struct sockaddr *addr,
485 const struct sockaddr *broadcast_addr,
486 const struct sockaddr *netmask,
487 socklen_t addrlen)
488{
489 in_addr_t ip;
490 const struct sockaddr_in *inaddr;
491
492 if (sizeof (struct sockaddr_in) != addrlen)
493 return GNUNET_OK; /* Only consider IPv4 for now */
494 inaddr = (const struct sockaddr_in *) addr;
495 ip = ntohl (inaddr->sin_addr.s_addr);
496 if (127 == ip >> 24) /* ignore loopback addresses */
497 return GNUNET_OK;
498 GNUNET_array_append (s_addrs, nips, ip);
499 LOG_DEBUG ("%d: Found IP: %s\n", rank, ip2str (ip));
500 addressmap_add (addrmap, rank, listen_port, ip);
501 return GNUNET_OK;
502}
503
504
505/**
506 * Callback function for data received from the network. Note that
507 * both "available" and "err" would be 0 if the read simply timed out.
508 *inaddr->sin_addr.s_addrinaddr->sin_addr.s_addr
509 * @param cls the read context
510 * @param buf pointer to received data
511 * @param available number of bytes availabe in "buf",
512 * possibly 0 (on errors)
513 * @param addr address of the sender
514 * @param addrlen size of addr
515 * @param errCode value of errno (on receiving errors)
516 */
517static void
518conn_reader(void *cls, const void *buf, size_t available,
519 const struct sockaddr * addr, socklen_t addrlen, int errCode)
520{
521 struct ReadContext *rc = cls;
522 uint32_t cid;
523
524 if (0 == available)
525 {
526 GNUNET_break (0);
527 goto clo_ret;
528 }
529 if ((NULL == buf) || (0 == available))
530 goto clo_ret;
531 (void) memcpy (&cid, buf, sizeof (uint32_t));
532 cid = ntohl (cid);
533 LOG_DEBUG ("%d: read id %u from connection\n", rank, cid);
534
535 clo_ret:
536 GNUNET_CONTAINER_DLL_remove (rhead, rtail, rc);
537 GNUNET_CONNECTION_destroy (rc->conn);
538 GNUNET_free (rc);
539}
540
541
542/**
543 * The connection that will be used by the daemon server for serving the client
544 */
545static struct GNUNET_CONNECTION_Handle *client_conn;
546
547
548/**
549 * Fork a worker process. This process forks a child which initiates the MSH
550 * execution protocol. Once the protocol authenticates the connecting client,
551 * it then forks and execs the remote command.
552 */
553static pid_t
554spawn_worker (struct GNUNET_NETWORK_Handle *sock)
555{
556 struct ChildProc *chld;
557 sigset_t sigset;
558 pid_t ret;
559
560 ret = fork ();
561 if (0 != ret)
562 return ret;
563 /* Child process continues here */
564 GNUNET_break (0 == sigemptyset (&sigset));
565 GNUNET_assert (0 == sigprocmask (SIG_SETMASK, &sigset, NULL));
566 client_conn = GNUNET_CONNECTION_create_from_existing (sock);
567 sock = NULL;
568 GNUNET_log_setup ("mshd-worker", NULL, NULL);
569 /* cleanup child processes as we are now not their parent */
570 while (NULL != (chld = chld_head))
571 {
572 GNUNET_CONTAINER_DLL_remove (chld_head, chld_tail, chld);
573 if (NULL != chld->sig_write)
574 GNUNET_DISK_file_close (chld->sig_write);
575 GNUNET_free (chld);
576 }
577 GNUNET_assert (MODE_SERV == mode);
578 GNUNET_SCHEDULER_cancel (shutdown_task);
579 shutdown_task = GNUNET_SCHEDULER_NO_TASK;
580 do_shutdown (NULL, NULL);
581 mode = MODE_WORKER;
582 GNUNET_SCHEDULER_shutdown ();
583 return 0;
584}
585
586
587/**
588 * A worker process we forked earlier has exited.
589 *
590 * @param cls the child context
591 * @param type the process status type
592 * @param long the return/exit code of the process
593 */
594static void
595worker_exit_cb (void *cls, enum GNUNET_OS_ProcessStatusType type, int code)
596{
597 struct ChildProc *chld = cls;
598
599 GNUNET_CONTAINER_DLL_remove (chld_head, chld_tail, chld);
600 GNUNET_free (chld);
601}
602
603
604/**
605 * Task to call accept and close on a listening socket
606 *
607 * @param cls NULL
608 * @param tc the scheduler task context
609 */
610static void
611accept_conn (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
612{
613 struct ReadContext *rctx;
614 struct GNUNET_NETWORK_Handle *sock;
615 struct GNUNET_CONNECTION_Handle *conn;
616 struct ChildProc *chld;
617 pid_t pid;
618
619 accept_task = GNUNET_SCHEDULER_NO_TASK;
620 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
621 {
622 goto clo_ret;
623 }
624 switch (mode)
625 {
626 case MODE_PROBE:
627 LOG_DEBUG ("%d: Got a probe connect\n", rank);
628 conn = GNUNET_CONNECTION_create_from_accept (NULL, NULL, listen_socket);
629 if (NULL == conn)
630 {
631 GNUNET_break (0);
632 goto clo_ret;
633 }
634 rctx = GNUNET_malloc (sizeof (struct ReadContext));
635 rctx->conn = conn;
636 rctx->in_receive = GNUNET_YES;
637 GNUNET_CONNECTION_receive (rctx->conn, sizeof (unsigned int),
638 GNUNET_TIME_UNIT_FOREVER_REL, conn_reader, rctx);
639 GNUNET_CONTAINER_DLL_insert_tail (rhead, rtail, rctx);
640 break;
641 case MODE_SERV:
642 sock = GNUNET_NETWORK_socket_accept (listen_socket, NULL, NULL);
643 pid = spawn_worker (sock);
644 if (0 == pid) /* state is cleared and hence we return */
645 return;
646 GNUNET_NETWORK_socket_close (sock);
647 if (-1 == pid)
648 {
649 GNUNET_break (0);
650 GNUNET_SCHEDULER_shutdown ();
651 goto clo_ret;
652 }
653 chld = GNUNET_new (struct ChildProc);
654 chld->pid = pid;
655 GNUNET_CONTAINER_DLL_insert (chld_head, chld_tail, chld);
656 MSH_monitor_process_pid (pid, worker_exit_cb, chld);
657 break;
658 case MODE_LOCAL_SERV:
659 GNUNET_assert (0);
660 case MODE_WORKER:
661 GNUNET_assert (0);
662 }
663 accept_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
664 listen_socket, &accept_conn, NULL);
665 return;
666
667 clo_ret:
668 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (listen_socket));
669 listen_socket = NULL;
670}
671
672
673/**
674 * Task to check if we received a shutdown signal through MPI message from
675 * instance 0. This task is to be run every 500ms
676 *
677 * @param cls NULL
678 * @param tc scheduler task context
679 */
680static void
681poll_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
682{
683 int flag;
684
685 poll_shutdown_task = GNUNET_SCHEDULER_NO_TASK;
686 if (0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason))
687 return;
688 flag = 0;
689 if (MPI_SUCCESS != MPI_Iprobe(0, MSH_MTYPE_SHUTDOWN, MPI_COMM_WORLD, &flag,
690 MPI_STATUS_IGNORE))
691 {
692 GNUNET_break (0);
693 goto reschedule;
694 }
695 if (0 == flag)
696 goto reschedule;
697 LOG_DEBUG ("Got termination signal. Shutting down\n");
698 GNUNET_SCHEDULER_shutdown (); /* We terminate */
699 return;
700
701 reschedule:
702 poll_shutdown_task = GNUNET_SCHEDULER_add_delayed (POLL_SHUTDOWN_INTERVAL,
703 &poll_shutdown, NULL);
704}
705
706
707/**
708 * Sends termination signal to all other instances through MPI messaging
709 */
710static void
711send_term_signal ()
712{
713 unsigned int cnt;
714 MPI_Request *req;
715
716 /* We broadcase termination signal. Can't use MPI_Bcast here... */
717 req = GNUNET_malloc (sizeof (MPI_Request) * (nproc - 1));
718 for (cnt = 1; cnt < nproc; cnt++)
719 {
720 GNUNET_assert (MPI_SUCCESS ==
721 MPI_Isend (&cnt, 1, MPI_INT, cnt, MSH_MTYPE_SHUTDOWN,
722 MPI_COMM_WORLD, &req[cnt - 1]));
723 }
724 GNUNET_assert (MPI_SUCCESS == MPI_Waitall (nproc - 1, req,
725 MPI_STATUSES_IGNORE));
726 GNUNET_free (req);
727}
728
729
730/**
731 * This callback is called when the process that we start from the forked local
732 * server exits. The local server is forked from MPI instances 0.
733 *
734 * @param cls the closure passed to MSH_monitor_process()
735 * @param type the process status type
736 * @param long the return/exit code of the process
737 */
738static void
739proc_exit_cb (void *cls, enum GNUNET_OS_ProcessStatusType type, int code)
740{
741 GNUNET_OS_process_destroy (proc);
742 proc = NULL;
743 LOG (GNUNET_ERROR_TYPE_INFO, "Main process died. Exiting.\n");
744 GNUNET_SCHEDULER_shutdown ();
745}
746
747
748/**
749 * This callback is called when the local server that we forked is exited.
750 * Shutdown our instance then.
751 *
752 * @param cls the closure passed to MSH_monitor_process()
753 * @param type the process status type
754 * @param long the return/exit code of the process
755 */
756static void
757local_serv_exit_cb (void *cls, enum GNUNET_OS_ProcessStatusType type, int code)
758{
759 struct ChildProc *chld = cls;
760
761 GNUNET_CONTAINER_DLL_remove (chld_head, chld_tail, chld);
762 if (NULL != chld->sig_write)
763 GNUNET_DISK_file_close (chld->sig_write);
764 GNUNET_free (chld);
765 LOG (GNUNET_ERROR_TYPE_INFO, "Local server died. Exiting. \n");
766 GNUNET_SCHEDULER_shutdown ();
767 if (0 == rank)
768 send_term_signal ();
769}
770
771
772/**
773 * Task which will initiate the daemon server
774 */
775static void
776daemon_server_run (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
777{
778 init_daemon_server ();
779 MSH_pmonitor_init ();
780 daemon_server_add_connection (client_conn);
781 shutdown_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
782 &do_shutdown, NULL);
783}
784
785
786/**
787 * Task which is run after receiving a signal thru the signal pipe. This task
788 * terminates is run only in the local worker process and terminates it.
789 *
790 * @param cls NULL
791 * @param tc scheduler task context.
792 */
793static void
794terminate_worker (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
795{
796 if (0 == (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason))
797 GNUNET_SCHEDULER_shutdown ();
798 GNUNET_DISK_file_close (worker_sigfd);
799 worker_sigfd = NULL;
800}
801
802
803/**
804 * Task which will initiate the local address lookup server
805 */
806static void
807local_server_run (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
808{
809 rmap = addressmap_create_reverse_mapping (addrmap);
810 init_local_server (unixpath);
811 GNUNET_NETWORK_socket_close (listen_socket);
812 listen_socket = NULL;
813 if (0 == rank)
814 {
815 MSH_pmonitor_init ();
816 proc = GNUNET_OS_start_process_vap (GNUNET_NO,
817 GNUNET_OS_INHERIT_STD_ALL,
818 NULL,
819 NULL,
820 NULL,
821 run_args[0],
822 run_args);
823 if (NULL == proc)
824 {
825 LOG_ERROR ("Unable to start process `%s'\n", run_args[0]);
826 GNUNET_SCHEDULER_shutdown ();
827 return;
828 }
829 MSH_monitor_process (proc, &proc_exit_cb, NULL);
830 }
831 GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == shutdown_task);
832 (void) GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
833 worker_sigfd,
834 &terminate_worker, NULL);
835 shutdown_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
836 &do_shutdown, NULL);
837}
838
839
840/**
841 * Task for running a round
842 *
843 * @param cls NULL
844 * @param tc scheduler task context
845 */
846static void
847run_round (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
848
849
850/**
851 * Schedules next round. If all the rounds are completed, call the next
852 */
853static void
854schedule_next_round ()
855{
856 struct ChildProc *chld;
857 struct ReadContext *rc;
858 struct GNUNET_DISK_PipeHandle *pipe;
859 struct GNUNET_DISK_FileHandle *read_end;
860 struct GNUNET_DISK_FileHandle *write_end;
861 sigset_t sigset;
862 intmax_t pid;
863
864 GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == rtask);
865 if (current_round < total_rounds)
866 {
867 rtask = GNUNET_SCHEDULER_add_now (&run_round, NULL);
868 return;
869 }
870 while (NULL != (rc = rhead))
871 {
872 GNUNET_CONTAINER_DLL_remove (rhead, rtail, rc);
873 GNUNET_CONNECTION_receive_cancel (rc->conn);
874 GNUNET_CONNECTION_destroy (rc->conn);
875 GNUNET_free (rc);
876 }
877 if (MPI_SUCCESS != MPI_Barrier (MPI_COMM_WORLD))
878 {
879 GNUNET_break (0);
880 return;
881 }
882 LOG_DEBUG ("Verification phase complete; commencing reduction phase\n");
883 if (GNUNET_SYSERR == reduce_ntree ())
884 {
885 GNUNET_SCHEDULER_shutdown ();
886 return;
887 }
888 pid = (intmax_t) getpid ();
889 GNUNET_assert (0 < asprintf (&unixpath, "/%ju.sock", pid));
890 hostsfile = GNUNET_DISK_mktemp ("MSHD_HOSTS");
891 if (GNUNET_OK != addressmap_write_hosts (addrmap, hostsfile))
892 {
893 GNUNET_SCHEDULER_shutdown ();
894 return;
895 }
896 GNUNET_assert (NULL != bitmap);
897 bitmap_destroy (bitmap);
898 bitmap = NULL;
899 setenv (MSHD_HOSTSFILE, hostsfile, 1);
900 setenv (MSHD_SOCK_NAME, unixpath, 1);
901 pipe = GNUNET_DISK_pipe (GNUNET_NO, GNUNET_NO, 0, 0);
902 GNUNET_assert (NULL != pipe);
903 read_end = GNUNET_DISK_pipe_detach_end (pipe, GNUNET_DISK_PIPE_END_READ);
904 write_end = GNUNET_DISK_pipe_detach_end (pipe, GNUNET_DISK_PIPE_END_WRITE);
905 GNUNET_DISK_pipe_close (pipe);
906 pipe = NULL;
907 pid = fork ();
908 if (-1 == pid)
909 {
910 GNUNET_DISK_file_close (read_end);
911 GNUNET_DISK_file_close (write_end);
912 GNUNET_SCHEDULER_shutdown ();
913 return;
914 }
915 if (0 == pid)
916 {
917
918 GNUNET_break (0 == sigemptyset (&sigset));
919 GNUNET_assert (0 == sigprocmask (SIG_SETMASK, &sigset, NULL));
920 GNUNET_DISK_file_close (write_end);
921 write_end = NULL;
922 worker_sigfd = read_end;
923 read_end = NULL;
924 GNUNET_log_setup ("mshd-local-serv", NULL, NULL);
925 mode = MODE_LOCAL_SERV;
926 GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != shutdown_task);
927 GNUNET_SCHEDULER_cancel (shutdown_task);
928 shutdown_task = GNUNET_SCHEDULER_NO_TASK;
929 GNUNET_SCHEDULER_shutdown ();
930 return;
931 }
932 GNUNET_assert (NULL != addrmap);
933 addressmap_destroy (addrmap);
934 addrmap = NULL;
935 if (NULL != s_addrs)
936 {
937 GNUNET_free (s_addrs);
938 s_addrs = NULL;
939 }
940 if (NULL != run_args)
941 {
942 free_argv (run_args);
943 run_args = NULL;
944 }
945 if (NULL != hostsfile)
946 {
947 GNUNET_free (hostsfile);
948 hostsfile = NULL;
949 }
950 chld = GNUNET_new (struct ChildProc);
951 chld->pid = pid;
952 chld->sig_write = write_end;
953 write_end = NULL;
954 GNUNET_DISK_file_close (read_end);
955 read_end = NULL;
956 GNUNET_CONTAINER_DLL_insert (chld_head, chld_tail, chld);
957 MSH_pmonitor_init ();
958 MSH_monitor_process_pid (pid, &local_serv_exit_cb, chld);
959 mode = MODE_SERV;
960 GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == accept_task);
961 accept_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
962 listen_socket, &accept_conn, NULL);
963 poll_shutdown_task = GNUNET_SCHEDULER_add_delayed (POLL_SHUTDOWN_INTERVAL,
964 &poll_shutdown, NULL);
965}
966
967
968/**
969 * Cleans up the address verification context
970 *
971 * @param ctx the context
972 */
973static void
974cleanup_verifyaddressctx (struct VerifyAddressesCtx *ctx)
975{
976 if (GNUNET_SCHEDULER_NO_TASK != ctx->close_task)
977 GNUNET_SCHEDULER_cancel (ctx->close_task);
978 if (NULL != ctx->transmit_handle)
979 GNUNET_CONNECTION_notify_transmit_ready_cancel (ctx->transmit_handle);
980 if (NULL != ctx->conn)
981 GNUNET_CONNECTION_destroy (ctx->conn);
982 GNUNET_CONTAINER_DLL_remove (vactx_head, vactx_tail, ctx);
983 GNUNET_free (ctx);
984}
985
986
987/**
988 * Finalise a round by freeing the resources used by it, cancel the accept task
989 * and schedule next round
990 *
991 * @param cls NULL
992 * @param tc scheduler task context
993 */
994static void
995finalise_round (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
996{
997 struct VerifyAddressesCtx *ctx;
998 unsigned int cnt;
999
1000 finalise_task = GNUNET_SCHEDULER_NO_TASK;
1001 GNUNET_SCHEDULER_cancel (accept_task);
1002 accept_task = GNUNET_SCHEDULER_NO_TASK;
1003 while (NULL != (ctx = vactx_head))
1004 {
1005 cleanup_verifyaddressctx (ctx);
1006 }
1007 for (cnt = 0; cnt < current_round_width; cnt++)
1008 instance_address_info_destroy (riainfos[cnt]);
1009 if (1 != bitmap_allset (bitmap))
1010 {
1011 LOG_ERROR ("Could not verify addresses of all hosts\n");
1012 GNUNET_SCHEDULER_shutdown ();
1013 return;
1014 }
1015 current_round++;
1016 schedule_next_round ();
1017}
1018
1019
1020/**
1021 * Task for closing a connection
1022 *
1023 * @param cls the verify address context
1024 * @param tc the scheduler task context
1025 */
1026static void
1027conn_close_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1028{
1029 struct VerifyAddressesCtx *ctx = cls;
1030 int lb;
1031 int source;
1032 int off;
1033
1034 ctx->close_task = GNUNET_SCHEDULER_NO_TASK;
1035 lb = rank - (current_round * round_width) - current_round_width + nproc;
1036 GNUNET_assert (0 <= lb);
1037 lb %= nproc;
1038 source = instance_address_info_get_rank (ctx->iainfo);
1039 if (lb <= source)
1040 off = source - lb;
1041 else
1042 off = nproc - lb + source;
1043 bitmap_set (bitmap, off, 1);
1044 addressmap_add (addrmap, instance_address_info_get_rank (ctx->iainfo),
1045 ctx->port, ctx->ip);
1046 cleanup_verifyaddressctx (ctx);
1047}
1048
1049
1050/**
1051 * Function called to notify a client about the connection
1052 * begin ready to queue more data. "buf" will be
1053 * NULL and "size" zero if the connection was closed for
1054 * writing in the meantime.
1055 *
1056 * @param cls closure
1057 * @param size number of bytes available in buf
1058 * @param buf where the callee should write the message
1059 * @return number of bytes written to buf
1060 */
1061static size_t
1062conn_write_cb (void *cls, size_t size, void *buf)
1063{
1064 struct VerifyAddressesCtx *ctx = cls;
1065 size_t rsize;
1066 uint32_t rank_;
1067
1068 ctx->transmit_handle = NULL;
1069 rsize = 0;
1070 if ((NULL == buf) || (0 == size))
1071 {
1072 goto clo_ret;
1073 }
1074 if (size < sizeof (uint32_t))
1075 {
1076 GNUNET_break (0);
1077 goto clo_ret;
1078 }
1079 switch (ctx->state)
1080 {
1081 case VERIFY_ADDRESS_CTX_WRITE:
1082 rank_ = htonl (rank);
1083 rsize = sizeof (uint32_t);
1084 (void) memcpy (buf, &rank_, rsize);
1085 ctx->transmit_handle =
1086 GNUNET_CONNECTION_notify_transmit_ready (ctx->conn, 0,
1087 GNUNET_TIME_UNIT_FOREVER_REL,
1088 &conn_write_cb, ctx);
1089 ctx->state = VERIFY_ADDRESS_CTX_CLOSE;
1090 return rsize;
1091 case VERIFY_ADDRESS_CTX_CLOSE:
1092 ctx->close_task = GNUNET_SCHEDULER_add_now (&conn_close_task, ctx);
1093 GNUNET_CONNECTION_destroy (ctx->conn);
1094 ctx->conn = NULL;
1095 return 0;
1096 default:
1097 GNUNET_assert (0);
1098 }
1099
1100 clo_ret:
1101 cleanup_verifyaddressctx (ctx);
1102 return size;
1103}
1104
1105
1106static unsigned int bmx;
1107
1108static int
1109address_iterator_cb (void *cls, uint16_t port, in_addr_t ip)
1110{
1111 struct VerifyAddressesCtx *ctx;
1112 struct InstanceAddrInfo *iainfo = cls;
1113 struct sockaddr_in in_addr;;
1114
1115 LOG_DEBUG ("%d: \t %d Opening connection to: %s\n", rank, bmx++, ip2str ((uint32_t) ip) );
1116 in_addr.sin_family = AF_INET;
1117 in_addr.sin_port = htons (port);
1118 in_addr.sin_addr.s_addr = htonl ((uint32_t) ip);
1119 ctx = GNUNET_malloc (sizeof (struct VerifyAddressesCtx));
1120 ctx->conn =
1121 GNUNET_CONNECTION_create_from_sockaddr (AF_INET,
1122 (const struct sockaddr *)
1123 &in_addr,
1124 sizeof (struct sockaddr_in));
1125 if (NULL == ctx->conn)
1126 {
1127 GNUNET_break (0);
1128 free (ctx);
1129 return GNUNET_SYSERR;
1130 }
1131 ctx->port = port;
1132 ctx->ip = ip;
1133 ctx->iainfo = iainfo;
1134 ctx->state = VERIFY_ADDRESS_CTX_WRITE;
1135 GNUNET_CONTAINER_DLL_insert_tail (vactx_head, vactx_tail, ctx);
1136 ctx->transmit_handle =
1137 GNUNET_CONNECTION_notify_transmit_ready (ctx->conn, sizeof (uint32_t),
1138 GNUNET_TIME_UNIT_FOREVER_REL,
1139 &conn_write_cb, ctx);
1140 return GNUNET_OK;
1141}
1142
1143
1144/**
1145 * Verify the addresses of an instance by connecting to the instance's listen
1146 * socket
1147 *
1148 * @param iainfo the instance's address information
1149 * @return GNUNET_OK upon success initialisation of the connection to instance's
1150 * listen socket (this does not mean that the connection is
1151 * established or an address is verified); GNUNET_SYSERR upon error
1152 */
1153static int
1154verify_addresses (struct InstanceAddrInfo *iainfo)
1155{
1156
1157 bmx = 0;
1158 if (GNUNET_OK != instance_address_info_iterate_addresses (iainfo,
1159 &address_iterator_cb,
1160 iainfo))
1161 return GNUNET_SYSERR;
1162 return GNUNET_OK;
1163}
1164
1165
1166/**
1167 * Parse a verfication message from a source for its address information
1168 *
1169 * @param msg the message to parse
1170 * @param source the MPI id of the instance which has sent this message
1171 * @return the instance's address information
1172 */
1173static struct InstanceAddrInfo *
1174parse_verify_address_msg (struct MSH_MSG_VerifyAddress *msg, int source)
1175{
1176 struct InstanceAddr *iaddr;
1177 struct InstanceAddrInfo *iainfo;
1178 size_t size;
1179 uint16_t nips;
1180 uint16_t cnt;
1181
1182 size = ntohs (msg->header.size);
1183 nips = ntohs (msg->nips);
1184 if (size != (sizeof (struct MSH_MSG_VerifyAddress)
1185 + (sizeof (uint32_t) * nips)))
1186 {
1187 LOG_ERROR ("Parsing failed\n");
1188 return NULL;
1189 }
1190 iainfo = instance_address_info_create (source);
1191 for (cnt = 0; cnt < nips; cnt++)
1192 {
1193 LOG_DEBUG ("%d: Parsed address: %s\n", rank, ip2str ((in_addr_t) ntohl (msg->ipaddrs[cnt])));
1194 iaddr = instance_address_create_sockaddr_in (ntohs (msg->port),
1195 (in_addr_t) ntohl (msg->ipaddrs[cnt]));
1196 GNUNET_break (GNUNET_OK == instance_address_info_add_address (iainfo, iaddr));
1197 }
1198 return iainfo;
1199}
1200
1201
1202/**
1203 * Receives the IP addresses to verify in the current round from instances
1204 *
1205 * @return an array containing the instance addresses; NULL upon a receive error
1206 */
1207static struct InstanceAddrInfo **
1208receive_addresses ()
1209{
1210 struct InstanceAddrInfo **iainfos;
1211 MPI_Status status;
1212 int cnt;
1213
1214 iainfos = GNUNET_malloc (sizeof (struct InstanceAddrInfo *) * current_round_width);
1215 for (cnt=0; cnt < current_round_width; cnt++)
1216 {
1217 struct MSH_MSG_VerifyAddress *msg;
1218 int rsize;
1219 int lb;
1220 int up;
1221 int source;
1222
1223 GNUNET_break (MPI_SUCCESS ==
1224 MPI_Probe (MPI_ANY_SOURCE, MSH_MTYPE_VERIFY_ADDRESSES,
1225 MPI_COMM_WORLD, &status));
1226 MPI_Get_elements (&status, MPI_BYTE, &rsize);
1227 /* We expect a message from peers with id p in the range:
1228 (rank - current_round * round_width - current_round_width) < p <= (rank - (current_round * round_width) -1) */
1229 up = rank - (current_round * round_width) - 1 + nproc;
1230 lb = (up - current_round_width) + nproc;
1231 GNUNET_assert (lb >= 0);
1232 GNUNET_assert (up >= 0);
1233 lb %= nproc;
1234 up %= nproc;
1235 source = status.MPI_SOURCE;
1236 GNUNET_assert (lb != up);
1237 if(lb < up)
1238 {
1239 if ((source <= lb) || (source > up))
1240 {
1241 GNUNET_break (0);
1242 goto err_ret;
1243 }
1244 }
1245 else if (up < lb)
1246 {
1247 if ((source > up) && (source <= lb))
1248 {
1249 GNUNET_break (0);
1250 goto err_ret;
1251 }
1252 }
1253 msg = GNUNET_malloc (rsize);
1254 if (MPI_SUCCESS != MPI_Recv (msg, rsize, MPI_BYTE, source,
1255 MSH_MTYPE_VERIFY_ADDRESSES, MPI_COMM_WORLD,
1256 MPI_STATUS_IGNORE))
1257 {
1258 GNUNET_break (0);
1259 goto err_ret;
1260 }
1261 LOG_DEBUG ("%d: Received message of size %d from %d\n", rank, rsize, source);
1262 if (NULL == (iainfos[cnt] = parse_verify_address_msg (msg, source)))
1263 {
1264 free (msg);
1265 goto err_ret;
1266 }
1267 free (msg);
1268 }
1269 return iainfos;
1270
1271 err_ret:
1272 for (cnt=0; cnt < current_round_width; cnt++)
1273 {
1274 if (NULL != iainfos[cnt])
1275 instance_address_info_destroy (iainfos[cnt]);
1276 }
1277 free (iainfos);
1278 return NULL;
1279}
1280
1281
1282/**
1283 * Send our addresses to an MPI processes
1284 *
1285 * @param rank the rank of the process which has to receive our request
1286 * @return GNUNET_OK on success; GNUNET_SYSERR upon error
1287 */
1288static int
1289send_addresses ()
1290{
1291 struct MSH_MSG_VerifyAddress *msg;
1292 struct MSH_MSG_VerifyAddress *cpys;
1293 MPI_Request *sreqs;
1294 size_t msize;
1295 int cnt;
1296 int ret;
1297 int target;
1298
1299 msize = sizeof (struct MSH_MSG_VerifyAddress) + (nips * sizeof (uint32_t));
1300 msg = GNUNET_malloc (msize);
1301 msg->header.size = htons (msize);
1302 msg->port = htons (listen_port);
1303 msg->nips = htons (nips);
1304 for (cnt = 0; cnt < nips; cnt++)
1305 {
1306 msg->ipaddrs[cnt] = htonl ((uint32_t) s_addrs[cnt]);
1307 }
1308 cpys = NULL;
1309 cpys = GNUNET_malloc (msize * current_round_width);
1310 sreqs = GNUNET_malloc (current_round_width * sizeof (MPI_Request));
1311 for (cnt=0; cnt < current_round_width; cnt++)
1312 {
1313 (void) memcpy (&cpys[cnt], msg, msize);
1314 target = (current_round * round_width) + cnt + 1;
1315 GNUNET_assert (target < nproc);
1316 target = (rank + target) % nproc;
1317 LOG_DEBUG ("%d: Sending message to %d\n", rank, target);
1318 ret = MPI_Isend (&cpys[cnt], msize, MPI_BYTE, target,
1319 MSH_MTYPE_VERIFY_ADDRESSES, MPI_COMM_WORLD, &sreqs[cnt]);
1320 if (MPI_SUCCESS != ret)
1321 break;
1322 }
1323 free (msg);
1324 msg = NULL;
1325 if (cnt != current_round_width)
1326 {
1327 for (cnt--; cnt >= 0; cnt--)
1328 {
1329 GNUNET_break (MPI_SUCCESS == MPI_Cancel (&sreqs[cnt]));
1330 GNUNET_break (MPI_SUCCESS == MPI_Wait (&sreqs[cnt], MPI_STATUS_IGNORE));
1331 }
1332 goto err_ret;
1333 }
1334 for (cnt=0; cnt < current_round_width; cnt++)
1335 {
1336 GNUNET_break (MPI_SUCCESS == MPI_Wait (&sreqs[cnt], MPI_STATUS_IGNORE));
1337 }
1338 LOG_DEBUG ("%d: Round: %d -- All messages sent successfully\n", rank, current_round);
1339 if (NULL != cpys)
1340 {
1341 free (cpys);
1342 cpys = NULL;
1343 }
1344
1345 err_ret:
1346 GNUNET_free_non_null (cpys);
1347 GNUNET_free_non_null (sreqs);
1348 return (MPI_SUCCESS == ret) ? GNUNET_OK : GNUNET_SYSERR;
1349}
1350
1351
1352/**
1353 * This functions opens a listen socket, sends this instance's IP addresses to
1354 * other instances and receives their IP addresses, starts accepting connections
1355 * on listen socket and verifies the IP addresses of other instances by
1356 * connecting to their listen sockets
1357 *
1358 * @return GNUNET_OK if verification is successful; GNUNET_SYSERR upon error (an error
1359 * message is logged)
1360 */
1361static int
1362run_round_ ()
1363{
1364 unsigned int cnt;
1365
1366 current_round_width = round_width;
1367 if ( (0 != ( (nproc - 1) % round_width)) && (current_round == ( (nproc - 1) / round_width)) )
1368 current_round_width = (nproc - 1) % round_width;
1369 if (GNUNET_SYSERR == send_addresses ())
1370 return GNUNET_SYSERR;
1371 if (NULL == (riainfos = receive_addresses ()))
1372 return GNUNET_SYSERR;
1373 accept_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
1374 listen_socket, &accept_conn, NULL);
1375
1376 if (MPI_SUCCESS != MPI_Barrier (MPI_COMM_WORLD))
1377 {
1378 GNUNET_break (0);
1379 return GNUNET_SYSERR;
1380 }
1381 for (cnt = 0; cnt < current_round_width; cnt++)
1382 verify_addresses (riainfos[cnt]);
1383 finalise_task =
1384 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
1385 (GNUNET_TIME_UNIT_SECONDS, 5),
1386 &finalise_round, NULL);
1387 return GNUNET_OK;
1388}
1389
1390
1391/**
1392 * Task for running a round
1393 *
1394 * @param cls NULL
1395 * @param tc scheduler task context
1396 */
1397static void
1398run_round (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1399{
1400 rtask = GNUNET_SCHEDULER_NO_TASK;
1401 if (GNUNET_OK != run_round_ ())
1402 GNUNET_SCHEDULER_shutdown ();
1403}
1404
1405
1406/**
1407 * Main function that will be run.
1408 *
1409 * @param cls closure
1410 * @param args remaining command-line arguments
1411 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
1412 * @param cfg configuration
1413 */
1414static void
1415run (void *cls, char *const *args, const char *cfgfile,
1416 const struct GNUNET_CONFIGURATION_Handle *cfg)
1417{
1418 struct sockaddr_in addr;
1419 socklen_t addrlen;
1420 unsigned int cnt;
1421
1422 LOG_DEBUG ("Running main task\n");
1423 if (0 == round_width)
1424 {
1425 LOG_ERROR ("Round width cannot be 0. Exiting\n");
1426 return;
1427 }
1428 if (nproc <= round_width)
1429 {
1430 LOG_ERROR ("Round width should be less than the number of processes\n");
1431 return;
1432 }
1433 for (cnt = 0; NULL != args[cnt]; cnt++);
1434 if (0 == cnt)
1435 {
1436 LOG_ERROR ("Need a command to execute\n");
1437 return;
1438 }
1439 run_args = copy_argv (args);
1440 bitmap = bitmap_create (round_width);
1441 addrmap = addressmap_create (nproc);
1442 addrlen = sizeof (struct sockaddr_in);
1443 (void) memset (&addr, 0, addrlen);
1444 addr.sin_addr.s_addr = INADDR_ANY; /* bind to all available addresses */
1445 listen_socket = open_listen_socket ((struct sockaddr *) &addr, addrlen, round_width);
1446 listen_port = ntohs (addr.sin_port);
1447 if (NULL == listen_socket)
1448 return;
1449 if (0 == listen_port)
1450 {
1451 GNUNET_break (0);
1452 goto clo_ret;
1453 }
1454 LOG_DEBUG ("Listening on port %u\n", listen_port);
1455 GNUNET_OS_network_interfaces_list (&net_if_processor, NULL);
1456 if (0 == nips)
1457 {
1458 LOG_ERROR ("No IP addresses found\n");
1459 return;
1460 }
1461 /* Number of rounds required to contact all processes except ourselves (round_width
1462 in parallel in each round) */
1463 total_rounds = ((nproc - 1) + (round_width - 1)) / round_width;
1464 schedule_next_round ();
1465 shutdown_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
1466 &do_shutdown, NULL);
1467 return;
1468
1469 clo_ret:
1470 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (listen_socket));
1471 listen_socket = NULL;
1472}
1473
1474
1475/**
1476 * The execution start point
1477 *
1478 * @param argc the number of arguments
1479 * @param argv the argument strings
1480 * @return 0 for successful termination; 1 for termination upon error
1481 */
1482int
1483main (int argc, char **argv)
1484{
1485 static const struct GNUNET_GETOPT_CommandLineOption options[] = {
1486 {'w', "round-width", "COUNT",
1487 "set the size of each round to COUNT",
1488 GNUNET_YES, &GNUNET_GETOPT_set_uint, &round_width},
1489 GNUNET_GETOPT_OPTION_END
1490 };
1491 static struct rlimit rlim;
1492 int ret;
1493
1494 ret = 1;
1495 round_width = 1;
1496 GNUNET_log_setup ("mshd", NULL, NULL);
1497 rlim.rlim_cur = RLIM_INFINITY;
1498 rlim.rlim_max = RLIM_INFINITY;
1499 if (0 != setrlimit (RLIMIT_CORE, &rlim))
1500 {
1501 LOG_ERROR ("Failed to set core file size limit to unlimited\n");
1502 return 1;
1503 }
1504 if (MPI_SUCCESS != MPI_Init(&argc, &argv))
1505 {
1506 LOG_ERROR ("Failed to initialise MPI\n");
1507 return 1;
1508 }
1509 if (MPI_SUCCESS != MPI_Comm_size (MPI_COMM_WORLD, &nproc))
1510 {
1511 LOG_ERROR ("Cannot determine the number of mshd processes\n");
1512 goto fail;
1513 }
1514 if (nproc <= round_width)
1515 {
1516 LOG_ERROR ("Given round width is greater than or equal to number of mshd processes\n");
1517 goto fail;
1518 }
1519 if (MPI_SUCCESS != MPI_Comm_rank (MPI_COMM_WORLD, &rank))
1520 {
1521 LOG_ERROR ("Cannot determine our MPI rank\n");
1522 goto fail;
1523 }
1524 if (GNUNET_OK != GNUNET_PROGRAM_run (argc, argv, "mshd", "mshd: MSH daemon",
1525 options, &run, NULL))
1526 {
1527 GNUNET_break (0);
1528 goto fail;
1529 }
1530 switch (mode)
1531 {
1532 case MODE_LOCAL_SERV:
1533 GNUNET_SCHEDULER_run (&local_server_run, NULL);
1534 break;
1535 case MODE_WORKER:
1536 GNUNET_SCHEDULER_run (&daemon_server_run, NULL);
1537 break;
1538 default:
1539 break;
1540 }
1541 ret = 0;
1542
1543 fail:
1544 if (MODE_LOCAL_SERV <= mode)
1545 _exit (ret);
1546 LOG_DEBUG ("Finalizing...\n");
1547 GNUNET_break (MPI_SUCCESS == MPI_Finalize());
1548 LOG_DEBUG ("Done\n");
1549 return ret;
1550}
diff --git a/src/mshd.h b/src/mshd.h
new file mode 100644
index 0000000..003687f
--- /dev/null
+++ b/src/mshd.h
@@ -0,0 +1,44 @@
1/**
2 * @file mshd.h
3 * @brief lists all external variables in the mshd binary
4 * @author Sree Harsha Totakura <sreeharsha@totakura.in>
5 */
6
7#ifndef MSHD_H_
8#define MSHD_H_
9
10#include "common.h"
11#include "addressmap.h"
12
13/**
14 * Our addressmap; created in the main(). Do not destroy elsewhere.
15 */
16extern AddressMap *addrmap;
17
18/**
19 * Reverse mapping of the address map
20 */
21extern struct ReverseAddressMap *rmap;
22
23/**
24 * Our instance rank
25 */
26extern int rank;
27
28/**
29 * round width
30 */
31extern unsigned int rwidth;
32
33/**
34 * Number of instances of mshd
35 */
36extern unsigned int nproc;
37
38/**
39 * Random hashcode for authentication
40 */
41extern struct GNUNET_HashCode shash;
42
43#endif /* MSHD_H_ */
44/* End of mshd.h */
diff --git a/src/mshd2.c b/src/mshd2.c
new file mode 100644
index 0000000..2721449
--- /dev/null
+++ b/src/mshd2.c
@@ -0,0 +1,1297 @@
1/**
2 * @file mshd.c
3 * @brief implementation of the MSH Daemon
4 * @author Sree Harsha Totakura <sreeharsha@totakura.in>
5 */
6
7#include "common.h"
8#include <gnunet/gnunet_util_lib.h>
9#include <mpi.h>
10#include "util.h"
11#include "mtypes.h"
12#include "bitmap.h"
13#include "addressmap.h"
14
15#define LOG(kind,...) \
16 GNUNET_log (kind, __VA_ARGS__)
17
18#define LOG_DEBUG(...) LOG(GNUNET_ERROR_TYPE_DEBUG, __VA_ARGS__)
19
20#define LOG_ERROR(...) LOG(GNUNET_ERROR_TYPE_ERROR, __VA_ARGS__)
21
22#define LOG_STRERROR(kind,cmd) \
23 GNUNET_log_from_strerror (kind, "mshd", cmd)
24
25/**
26 * Polling interval for checking termination signal
27 */
28#define POLL_SHUTDOWN_INTERVAL \
29 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 500)
30
31/**
32 * Context for verifying addresses
33 */
34struct VerifyAddressesCtx
35{
36 /**
37 * The DLL next ptr
38 */
39 struct VerifyAddressesCtx *next;
40
41 /**
42 * The DLL prev ptr
43 */
44 struct VerifyAddressesCtx *prev;
45
46 /**
47 * The instance addresses
48 */
49 struct InstanceAddrInfo *iainfo;
50
51 /**
52 * The connection handle to the received instance address
53 */
54 struct GNUNET_CONNECTION_Handle *conn;
55
56 /**
57 * The transmit handle for the above connection
58 */
59 struct GNUNET_CONNECTION_TransmitHandle *transmit_handle;
60
61 /**
62 * task to close the connection
63 */
64 GNUNET_SCHEDULER_TaskIdentifier close_task;
65
66 /**
67 * state for the context
68 */
69 enum {
70 VERIFY_ADDRESS_CTX_WRITE,
71
72 VERIFY_ADDRESS_CTX_CLOSE
73 } state;
74
75 /**
76 * the ip address
77 */
78 in_addr_t ip;
79
80 /**
81 * the port number
82 */
83 uint16_t port;
84
85};
86
87
88/**
89 * Context information for reading from incoming connections
90 */
91struct ReadContext
92{
93 /**
94 * next pointer for DLL
95 */
96 struct ReadContext *next;
97
98 /**
99 * prev pointer for DLL
100 */
101 struct ReadContext *prev;
102
103 /**
104 * The connection
105 */
106 struct GNUNET_CONNECTION_Handle *conn;
107
108 /**
109 * are we waiting for a read on the above connection
110 */
111 int in_receive;
112};
113
114
115/**
116 * The mode of the current listen socket;
117 */
118enum ListenMode
119{
120 /**
121 * Mode in which the listen socket accepts connections from other instances
122 * and closes them immediately after reading some data. The incoming
123 * connections are used to verify which IP addresses of this instance are
124 * reachable from other instances
125 */
126 MODE_PROBE,
127
128 /**
129 * In this mode the listen socket accepts requests for starting remote processes
130 */
131 MODE_SERV,
132
133 /**
134 * Simple worker mode. No listening is done.
135 */
136 MODE_WORKER,
137
138 /**
139 * Worker mode with protocol.
140 */
141 MODE_PROTOWORKER
142
143} mode;
144
145
146/**
147 * Mapping for instance addresses
148 */
149AddressMap *addrmap;
150
151/**
152 * Reverse mapping of the address map
153 */
154struct ReverseAddressMap *rmap;
155
156/**
157 * Rank of this process
158 */
159int rank;
160
161/**
162 * width of the round -- how many other mshd instances verify our IP addresses
163 * in a round
164 */
165unsigned int rwidth;
166
167/**
168 * The number of total mshd processes
169 */
170int nproc;
171
172
173/****************************/
174/* static variables */
175/****************************/
176
177/**
178 * DLL head for address verification contexts
179 */
180static struct VerifyAddressesCtx *vactx_head;
181
182/**
183 * DLL tail for address verification contexts
184 */
185static struct VerifyAddressesCtx *vactx_tail;
186
187/**
188 * Array of our IP addresses in network-byte format
189 */
190static in_addr_t *s_addrs;
191
192/**
193 * network handle for the listen socket
194 */
195static struct GNUNET_NETWORK_Handle *listen_socket;
196
197/**
198 * The process handle of the process started by instance running with rank 0
199 */
200static struct GNUNET_OS_Process *proc;
201
202/**
203 * Task for running a round
204 */
205static GNUNET_SCHEDULER_TaskIdentifier rtask;
206
207/**
208 * Task for asynchronous accept on the socket
209 */
210static GNUNET_SCHEDULER_TaskIdentifier atask;
211
212/**
213 * Task for finalising a round
214 */
215static GNUNET_SCHEDULER_TaskIdentifier finalise_task;
216
217/**
218 * Task for waiting for a shutdown signal
219 */
220static GNUNET_SCHEDULER_TaskIdentifier sigread_task;
221
222/**
223 * Bitmap for checking which MPI processes have verified our addresses in the
224 * current round
225 */
226static struct BitMap *bitmap;
227
228/**
229 * Instances addresses learnt in the current round
230 */
231struct InstanceAddrInfo **riainfos;
232
233/**
234 * head for read context DLL
235 */
236static struct ReadContext *rhead;
237
238/**
239 * tail for read context DLL
240 */
241static struct ReadContext *rtail;
242
243/**
244 * arguments representing the command to run and its arguments
245 */
246static char **run_args;
247
248/**
249 * the process handle for the command to run
250 */
251static struct GNUNET_OS_Process *process;
252
253/**
254 * The path of the unix domain socket we use for communication with local MSH clients
255 */
256static char *unixpath;
257
258/**
259 * The file where the addresses of available hosts are written to
260 */
261static char *hostsfile;
262
263/**
264 * shutdown task
265 */
266GNUNET_SCHEDULER_TaskIdentifier shutdown_task;
267
268/**
269 * Shutdown polling task
270 */
271GNUNET_SCHEDULER_TaskIdentifier poll_shutdown_task;
272
273/**
274 * Random hashcode for authentication
275 */
276struct GNUNET_HashCode shash;
277
278/**
279 * Number of IP addresses
280 */
281static unsigned int nips;
282
283/**
284 * Current IP verification round
285 */
286static unsigned int current_round;
287
288/**
289 * Do we have to create a pty
290 */
291static int need_pty;
292
293/**
294 * The port number of our local socket
295 */
296uint16_t listen_port;
297
298
299/**
300 * Perform cleanup for shutdown
301 *
302 * @param cls NULL
303 * @param tc scheduler task context
304 */
305static void
306do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
307{
308 shutdown_task = GNUNET_SCHEDULER_NO_TASK;
309 switch (mode)
310 {
311 case MODE_PROBE:
312 break;
313 case MODE_SERV:
314 shutdown_local_server ();
315 MSH_pmonitor_shutdown ();
316 break;
317 case MODE_WORKER:
318 break;
319 case MODE_PROTOWORKER:
320 shutdown_daemon_server ();
321 break;
322 }
323 if (GNUNET_SCHEDULER_NO_TASK != accept_task)
324 {
325 GNUNET_SCHEDULER_cancel (accept_task);
326 accept_task = GNUNET_SCHEDULER_NO_TASK;
327 }
328 if (NULL != listen_socket)
329 {
330 GNUNET_NETWORK_socket_close (listen_socket);
331 listen_socket = NULL;
332 }
333 if (NULL != bitmap)
334 {
335 bitmap_destroy (bitmap);
336 bitmap = NULL;
337 }
338 if (NULL != addrmap)
339 {
340 addressmap_destroy (addrmap);
341 addressmap = NULL;
342 }
343 if (NULL != rmap)
344 {
345 reverse_map_destroy (rmap);
346 rmap = NULL;
347 }
348 GNUNET_free_non_null (s_addrs);
349 s_addrs = NULL;
350 if (NULL != run_args)
351 {
352 free_argv (run_args);
353 run_args = NULL;
354 }
355 GNUNET_free_non_null (unixpath);
356 unixpath = NULL;
357 if (NULL != hostsfile)
358 {
359 (void) unlink (hostsfile);
360 GNUNET_free (hostsfile);
361 hostsfile = NULL;
362 }
363}
364
365
366/**
367 * Callback function invoked for each interface found.
368 *
369 * @param cls closure
370 * @param name name of the interface (can be NULL for unknown)
371 * @param isDefault is this presumably the default interface
372 * @param addr address of this interface (can be NULL for unknown or unassigned)
373 * @param broadcast_addr the broadcast address (can be NULL for unknown or unassigned)
374 * @param netmask the network mask (can be NULL for unknown or unassigned))
375 * @param addrlen length of the address
376 * @return GNUNET_OK to continue iteration, GNUNET_SYSERR to abort
377 */
378static int net_if_processor (void *cls, const char *name,
379 int isDefault,
380 const struct sockaddr *addr,
381 const struct sockaddr *broadcast_addr,
382 const struct sockaddr *netmask,
383 socklen_t addrlen)
384{
385 char *hostip;
386 in_addr_t ip;
387 const struct sockaddr_in *inaddr;
388
389 if (sizeof (struct sockaddr_in) != addrlen)
390 return GNUNET_OK; /* Only consider IPv4 for now */
391 inaddr = (const struct sockaddr_in *) addr;
392 ip = ntohl (inaddr->sin_addr.s_addr);
393 if (127 == ip >> 24) /* ignore loopback addresses */
394 return GNUNET_OK;
395 GNUNET_array_append (s_addrs, nips, ip);
396 LOG_DEBUG ("%d: Found IP: %s\n", rank, ip2str (ip));
397 addressmap_add (addrmap, rank, listen_port, ip);
398 return GNUNET_OK;
399}
400
401
402/**
403 * Callback function for data received from the network. Note that
404 * both "available" and "err" would be 0 if the read simply timed out.
405 *inaddr->sin_addr.s_addrinaddr->sin_addr.s_addr
406 * @param cls the read context
407 * @param buf pointer to received data
408 * @param available number of bytes availabe in "buf",
409 * possibly 0 (on errors)
410 * @param addr address of the sender
411 * @param addrlen size of addr
412 * @param errCode value of errno (on receiving errors)
413 */
414static void
415conn_reader(void *cls, const void *buf, size_t available,
416 const struct sockaddr * addr, socklen_t addrlen, int errCode)
417{
418 struct ReadContext *rc = cls;
419 uint32_t cid;
420
421 if (0 == available)
422 {
423 GNUNET_break (0);
424 goto clo_ret;
425 }
426 if ((NULL == buf) || (0 == available))
427 goto clo_ret;
428 (void) memcpy (&cid, buf, sizeof (uint32_t));
429 cid = ntohl (cid);
430 LOG_DEBUG ("%d: read id %u from connection\n", rank, cid);
431
432 clo_ret:
433 GNUNET_CONTAINER_DLL_remove (rhead, rtail, rc);
434 GNUNET_CONNECTION_destroy (rc->conn);
435 GNUNET_free (rc);
436}
437
438
439/**
440 * Fork a worker process. This process sets up a PTY if needed, forks a child
441 * which exec's the binary to start and manages the communication between the
442 * binary and network if given a network connection.
443 */
444static pid_t
445spawn_worker (int do_protocol)
446{
447 struct GNUNET_NETWORK_Handle *sock;
448 struct GNUNET_CONNECTION_Handle *conn;
449 pid_t ret;
450
451 ret = fork ();
452 if (0 != ret)
453 return ret;
454 /* Child process continues here */
455 if (do_protocol)
456 {
457 GNUNET_assert (MODE_SERV == mode);
458 GNUNET_assert (NULL != listen_socket);
459 sock = GNUNET_NETWORK_socket_accept (listen_socket, NULL, NULL);
460 conn = GNUNET_CONNECTION_create_from_existing (sock);
461 }
462 GNUNET_SCHEDULER_cancel (shutdown_task);
463 shutdown_task = GNUNET_SCHEDULER_NO_TASK;
464 do_shutdown (NULL, NULL);
465 mode = MODE_WORKER;
466 if (do_protocol)
467 {
468 mode = MODE_PROTOWORKER;
469 init_daemon_server ();
470 daemon_server_add_connection (conn);
471 }
472 return 0;
473}
474
475
476/**
477 * Task to call accept and close on a listening socket
478 *
479 * @param cls NULL
480 * @param tc the scheduler task context
481 */
482static void
483accept_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
484{
485 struct ReadContext *rctx;
486 struct GNUNET_CONNECTION_Handle *conn;
487 pid_t pid;
488 int csock;
489
490 atask = GNUNET_SCHEDULER_NO_TASK;
491 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
492 {
493 goto clo_ret;
494 }
495 switch (mode)
496 {
497 case MODE_PROBE:
498 LOG_DEBUG ("%d: Got a probe connect\n", rank);
499 conn = GNUNET_CONNECTION_create_from_accept (NULL, NULL, listen_socket);
500 if (NULL == conn)
501 {
502 GNUNET_break (0);
503 goto clo_ret;
504 }
505 rctx = GNUNET_malloc (sizeof (struct ReadContext));
506 rctx->conn = conn;
507 rctx->in_receive = GNUNET_YES;
508 GNUNET_CONNECTION_receive (rctx->conn, sizeof (unsigned int),
509 GNUNET_TIME_UNIT_FOREVER_REL, conn_reader, rctx);
510 GNUNET_CONTAINER_DLL_insert_tail (rhead, rtail, rctx);
511 break;
512 case MODE_SERV:
513 pid = spawn_worker (1);
514 if (-1 == pid)
515 {
516 GNUNET_break (0);
517 GNUNET_SCHEDULER_shutdown (0);
518 goto clo_ret;
519 }
520 if (0 == pid) /* state is cleared and hence we return */
521 return;
522 break;
523 case MODE_WORKER:
524 case MODE_PROTOWORKER:
525 GNUNET_assert (0);
526 }
527 atask = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
528 listen_socket, &accept_task, NULL);
529 return;
530
531 clo_ret:
532 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (listen_socket));
533 listen_socket = NULL;
534}
535
536
537/**
538 * Task to check if we received a shutdown signal through MPI message from
539 * instance 0. This task is to be run every 500ms
540 *
541 * @param cls NULL
542 * @param tc scheduler task context
543 */
544static void
545poll_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
546{
547 int flag;
548
549 poll_shutdown_task = GNUNET_SCHEDULER_NO_TASK;
550 if (0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason))
551 return;
552 flag = 0;
553 if (MPI_SUCCESS != MPI_Iprobe(0, MSH_MTYPE_SHUTDOWN, MPI_COMM_WORLD, &flag,
554 MPI_STATUS_IGNORE))
555 {
556 GNUNET_break (0);
557 goto reschedule;
558 }
559 if (0 == flag)
560 goto reschedule;
561 LOG_DEBUG ("Got termination signal. Shutting down\n");
562 GNUNET_SCHEDULER_shutdown (); /* We terminate */
563 return;
564
565 reschedule:
566 poll_shutdown_task = GNUNET_SCHEDULER_add_delayed (POLL_SHUTDOWN_INTERVAL,
567 &poll_shutdown, NULL);
568}
569
570
571/**
572 * Sends termination signal to all other instances through MPI messaging
573 */
574static void
575send_term_signal ()
576{
577 unsigned int cnt;
578 MPI_Request *req;
579
580 /* We broadcase termination signal. Can't use MPI_Bcast here... */
581 req = GNUNET_malloc (sizeof (MPI_Request) * (nproc - 1));
582 for (cnt = 1; cnt < nproc; cnt++)
583 {
584 GNUNET_assert (MPI_SUCCESS ==
585 MPI_Isend (&cnt, 1, MPI_INT, cnt, MSH_MTYPE_SHUTDOWN,
586 MPI_COMM_WORLD, &req[cnt - 1]));
587 }
588 GNUNET_assert (MPI_SUCCESS == MPI_Waitall (nproc - 1, req,
589 MPI_STATUSES_IGNORE));
590 GNUNET_free (req);
591}
592
593
594/**
595 * Callbacks of this type can be supplied to MSH_monitor_process() to be
596 * notified when the corresponding processes exits.
597 *
598 * @param cls the closure passed to MSH_monitor_process()
599 * @param type the process status type
600 * @param long the return/exit code of the process
601 */
602static void
603proc_exit_cb (void *cls, enum GNUNET_OS_ProcessStatusType type, int code)
604{
605 GNUNET_OS_process_destroy (proc);
606 proc = NULL;
607 LOG (GNUNET_ERROR_TYPE_INFO, "Main process died. Exiting.\n");
608 GNUNET_SCHEDULER_shutdown ();
609 send_term_signal ();
610}
611
612
613/**
614 * Task for running a round
615 *
616 * @param cls NULL
617 * @param tc scheduler task context
618 */
619static void
620run_round (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
621
622
623/**
624 * Schedules next round. If all the rounds are completed, call the next
625 */
626static void
627schedule_next_round ()
628{
629 pid_t pid;
630 int total_rounds;
631
632 GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == rtask);
633 /* Number of rounds required to contact all processes except ourselves (rwidth
634 in parallel in each round) */
635 total_rounds = ((nproc - 1) + (rwidth - 1)) / rwidth;
636 if (current_round < total_rounds)
637 {
638 rtask = GNUNET_SCHEDULER_add_now (&run_round, NULL);
639 return;
640 }
641 if (MPI_SUCCESS != MPI_Barrier (MPI_COMM_WORLD))
642 {
643 GNUNET_break (0);
644 return;
645 }
646 LOG_DEBUG ("Verification phase complete; commencing reduction phase\n");
647 GNUNET_break (GNUNET_OK == reduce_ntree ());
648 addressmap_print (addrmap);
649 rmap = addressmap_create_reverse_mapping (addrmap);
650 pid = getpid ();
651 GNUNET_assert (0 < asprintf (&unixpath, "%ju.sock", (intmax_t) pid));
652 setenv (MSHD_SOCK_NAME, unixpath, 1);
653 hostsfile = GNUNET_DISK_mktemp ("MSHD_HOSTS");
654 if (GNUNET_OK != addressmap_write_hosts (addrmap, hostsfile))
655 {
656 GNUNET_SCHEDULER_shutdown ();
657 return;
658 }
659 setenv (MSHD_HOSTSFILE, hostsfile, 1);
660 init_local_server (unixpath);
661 MSH_pmonitor_init ();
662 mode = MODE_SERV;
663 GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == atask);
664 atask = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
665 listen_socket, &accept_task, NULL);
666 if (0 == rank)
667 {
668 pid = spawn_worker (0);
669 if (-1 == pid)
670 {
671 GNUNET_break (0);
672 GNUNET_SCHEDULER_shutdown (0);
673 return;
674 }
675 if (0 != pid)
676 {
677 MSH_monitor_process_pid (proc, &proc_exit_cb, NULL);
678 goto end;
679 }
680 if (reverse_connect)
681 do_reverse_connect ();
682 if (need_pty)
683 create_pty ();
684 fork_and_exec (run_args[0]);
685 return;
686 }
687 end:
688 poll_shutdown_task = GNUNET_SCHEDULER_add_delayed (POLL_SHUTDOWN_INTERVAL,
689 &poll_shutdown, NULL);
690}
691
692
693/**
694 * Cleans up the address verification context
695 *
696 * @param ctx the context
697 */
698static void
699cleanup_verifyaddressctx (struct VerifyAddressesCtx *ctx)
700{
701 if (GNUNET_SCHEDULER_NO_TASK != ctx->close_task)
702 GNUNET_SCHEDULER_cancel (ctx->close_task);
703 if (NULL != ctx->conn)
704 GNUNET_CONNECTION_destroy (ctx->conn);
705 GNUNET_CONTAINER_DLL_remove (vactx_head, vactx_tail, ctx);
706 GNUNET_free (ctx);
707}
708
709
710/**
711 * Finalise a round by freeing the resources used by it, cancel the accept task
712 * and schedule next round
713 *
714 * @param cls NULL
715 * @param tc scheduler task context
716 */
717static void
718finalise_round (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
719{
720 struct VerifyAddressesCtx *ctx;
721 unsigned int cnt;
722
723 finalise_task = GNUNET_SCHEDULER_NO_TASK;
724 GNUNET_SCHEDULER_cancel (atask);
725 atask = GNUNET_SCHEDULER_NO_TASK;
726 while (NULL != (ctx = vactx_head))
727 {
728 cleanup_verifyaddressctx (ctx);
729 }
730 for (cnt = 0; cnt < rwidth; cnt++)
731 instance_address_info_destroy (riainfos[cnt]);
732 if (1 != bitmap_allset (bitmap))
733 {
734 LOG_ERROR ("Could not verify addresses of all hosts\n");
735 GNUNET_SCHEDULER_shutdown ();
736 return;
737 }
738 current_round++;
739 schedule_next_round ();
740}
741
742
743/**
744 * Task for closing a connection
745 *
746 * @param cls the verify address context
747 * @param tc the scheduler task context
748 */
749static void
750conn_close_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
751{
752 struct VerifyAddressesCtx *ctx = cls;
753 int lb;
754 int source;
755 int off;
756
757 ctx->close_task = GNUNET_SCHEDULER_NO_TASK;
758 lb = rank - (current_round * rwidth) - rwidth + nproc;
759 GNUNET_assert (0 <= lb);
760 lb %= nproc;
761 source = instance_address_info_get_rank (ctx->iainfo);
762 if (lb <= source)
763 off = source - lb;
764 else
765 off = nproc - lb + source;
766 bitmap_set (bitmap, off, 1);
767 addressmap_add (addrmap, instance_address_info_get_rank (ctx->iainfo),
768 ctx->port, ctx->ip);
769 cleanup_verifyaddressctx (ctx);
770}
771
772
773/**
774 * Function called to notify a client about the connection
775 * begin ready to queue more data. "buf" will be
776 * NULL and "size" zero if the connection was closed for
777 * writing in the meantime.
778 *
779 * @param cls closure
780 * @param size number of bytes available in buf
781 * @param buf where the callee should write the message
782 * @return number of bytes written to buf
783 */
784static size_t
785conn_write_cb (void *cls, size_t size, void *buf)
786{
787 struct VerifyAddressesCtx *ctx = cls;
788 size_t rsize;
789 uint32_t rank_;
790
791 ctx->transmit_handle = NULL;
792 rsize = 0;
793 if ((NULL == buf) || (0 == size))
794 {
795 goto clo_ret;
796 }
797 if (size < sizeof (uint32_t))
798 {
799 GNUNET_break (0);
800 goto clo_ret;
801 }
802 switch (ctx->state)
803 {
804 case VERIFY_ADDRESS_CTX_WRITE:
805 rank_ = htonl (rank);
806 rsize = sizeof (uint32_t);
807 (void) memcpy (buf, &rank_, rsize);
808 ctx->transmit_handle =
809 GNUNET_CONNECTION_notify_transmit_ready (ctx->conn, 0,
810 GNUNET_TIME_UNIT_FOREVER_REL,
811 &conn_write_cb, ctx);
812 ctx->state = VERIFY_ADDRESS_CTX_CLOSE;
813 return rsize;
814 case VERIFY_ADDRESS_CTX_CLOSE:
815 ctx->close_task = GNUNET_SCHEDULER_add_now (&conn_close_task, ctx);
816 GNUNET_CONNECTION_destroy (ctx->conn);
817 ctx->conn = NULL;
818 return 0;
819 default:
820 GNUNET_assert (0);
821 }
822
823 clo_ret:
824 cleanup_verifyaddressctx (ctx);
825 return size;
826}
827
828
829static unsigned int bmx;
830
831static int
832address_iterator_cb (void *cls, uint16_t port, in_addr_t ip)
833{
834 struct VerifyAddressesCtx *ctx;
835 struct InstanceAddrInfo *iainfo = cls;
836 struct sockaddr_in in_addr;;
837
838 LOG_DEBUG ("%d: \t %d Opening connection to: %s\n", rank, bmx++, ip2str ((uint32_t) ip) );
839 in_addr.sin_family = AF_INET;
840 in_addr.sin_port = htons (port);
841 in_addr.sin_addr.s_addr = htonl ((uint32_t) ip);
842 ctx = GNUNET_malloc (sizeof (struct VerifyAddressesCtx));
843 ctx->conn =
844 GNUNET_CONNECTION_create_from_sockaddr (AF_INET,
845 (const struct sockaddr *)
846 &in_addr,
847 sizeof (struct sockaddr_in));
848 if (NULL == ctx->conn)
849 {
850 GNUNET_break (0);
851 free (ctx);
852 return GNUNET_SYSERR;
853 }
854 ctx->port = port;
855 ctx->ip = ip;
856 ctx->iainfo = iainfo;
857 ctx->state = VERIFY_ADDRESS_CTX_WRITE;
858 GNUNET_CONTAINER_DLL_insert_tail (vactx_head, vactx_tail, ctx);
859 ctx->transmit_handle =
860 GNUNET_CONNECTION_notify_transmit_ready (ctx->conn, sizeof (uint32_t),
861 GNUNET_TIME_UNIT_FOREVER_REL,
862 &conn_write_cb, ctx);
863 return GNUNET_OK;
864}
865
866
867/**
868 * Verify the addresses of an instance by connecting to the instance's listen
869 * socket
870 *
871 * @param iainfo the instance's address information
872 * @return GNUNET_OK upon success initialisation of the connection to instance's
873 * listen socket (this does not mean that the connection is
874 * established or an address is verified); GNUNET_SYSERR upon error
875 */
876static int
877verify_addresses (struct InstanceAddrInfo *iainfo)
878{
879
880 struct InstanceAddr *iaddr;
881
882 bmx = 0;
883 if (GNUNET_OK != instance_address_info_iterate_addresses (iainfo,
884 &address_iterator_cb,
885 iainfo))
886 return GNUNET_SYSERR;
887 return GNUNET_OK;
888}
889
890
891/**
892 * Parse a verfication message from a source for its address information
893 *
894 * @param msg the message to parse
895 * @param source the MPI id of the instance which has sent this message
896 * @return the instance's address information
897 */
898static struct InstanceAddrInfo *
899parse_verify_address_msg (struct MSH_MSG_VerifyAddress *msg, int source)
900{
901 struct InstanceAddr *iaddr;
902 struct InstanceAddrInfo *iainfo;
903 size_t size;
904 uint16_t nips;
905 uint16_t cnt;
906
907 size = ntohs (msg->header.size);
908 nips = ntohs (msg->nips);
909 if (size != (sizeof (struct MSH_MSG_VerifyAddress)
910 + (sizeof (uint32_t) * nips)))
911 {
912 LOG_ERROR ("Parsing failed\n");
913 return NULL;
914 }
915 iainfo = instance_address_info_create (source);
916 for (cnt = 0; cnt < nips; cnt++)
917 {
918 LOG_DEBUG ("%d: Parsed address: %s\n", rank, ip2str ((in_addr_t) ntohl (msg->ipaddrs[cnt])));
919 iaddr = instance_address_create_sockaddr_in (ntohs (msg->port),
920 (in_addr_t) ntohl (msg->ipaddrs[cnt]));
921 GNUNET_break (GNUNET_OK == instance_address_info_add_address (iainfo, iaddr));
922 }
923 return iainfo;
924}
925
926
927/**
928 * Receives the IP addresses to verify in the current round from instances
929 *
930 * @return an array containing the instance addresses; NULL upon a receive error
931 */
932static struct InstanceAddrInfo **
933receive_addresses ()
934{
935 struct InstanceAddrInfo **iainfos;
936 MPI_Status status;
937 int cnt;
938
939 iainfos = GNUNET_malloc (sizeof (struct InstanceAddrInfo *) * rwidth);
940 for (cnt=0; cnt < rwidth; cnt++)
941 {
942 struct MSH_MSG_VerifyAddress *msg;
943 int rsize;
944 int lb;
945 int up;
946 int source;
947 int ret;
948
949 GNUNET_break (MPI_SUCCESS ==
950 MPI_Probe (MPI_ANY_SOURCE, MSH_MTYPE_VERIFY_ADDRESSES,
951 MPI_COMM_WORLD, &status));
952 MPI_Get_elements (&status, MPI_BYTE, &rsize);
953 /* We expect a message from peers with id p in the range:
954 (rank - current_round * rwidth - rwidth) <= p <= (rank - (current_round * rwidth) -1) */
955 lb = rank - current_round * rwidth - rwidth + nproc;
956 up = rank - (current_round * rwidth) - 1 + nproc;
957 GNUNET_assert (lb >= 0);
958 GNUNET_assert (up >= 0);
959 lb %= nproc;
960 up %= nproc;
961 source = status.MPI_SOURCE;
962 if (lb == up)
963 {
964 if (source != lb)
965 {
966 GNUNET_break (0);
967 LOG_ERROR ("%d: Error: source %d; lb: %d; up: %d\n", rank, source, lb, up);
968 goto err_ret;
969 }
970 }
971 else if(lb < up)
972 {
973 if ((source < lb) || (source > up))
974 {
975 GNUNET_break (0);
976 goto err_ret;
977 }
978 }
979 else if (up < lb)
980 {
981 if ((source > up) && (source < lb))
982 {
983 GNUNET_break (0);
984 goto err_ret;
985 }
986 }
987 msg = GNUNET_malloc (rsize);
988 if (MPI_SUCCESS != MPI_Recv (msg, rsize, MPI_BYTE, source,
989 MSH_MTYPE_VERIFY_ADDRESSES, MPI_COMM_WORLD,
990 MPI_STATUS_IGNORE))
991 {
992 GNUNET_break (0);
993 goto err_ret;
994 }
995 LOG_DEBUG ("%d: Received message of size %d from %d\n", rank, rsize, source);
996 if (NULL == (iainfos[cnt] = parse_verify_address_msg (msg, source)))
997 {
998 free (msg);
999 goto err_ret;
1000 }
1001 free (msg);
1002 }
1003 return iainfos;
1004
1005 err_ret:
1006 for (cnt=0; cnt < rwidth; cnt++)
1007 {
1008 if (NULL != iainfos[cnt])
1009 instance_address_info_destroy (iainfos[cnt]);
1010 }
1011 free (iainfos);
1012 return NULL;
1013}
1014
1015
1016/**
1017 * Send our addresses to an MPI processes
1018 *
1019 * @param rank the rank of the process which has to receive our request
1020 * @return GNUNET_OK on success; GNUNET_SYSERR upon error
1021 */
1022static int
1023send_addresses ()
1024{
1025 struct MSH_MSG_VerifyAddress *msg;
1026 struct MSH_MSG_VerifyAddress *cpys;
1027 MPI_Request *sreqs;
1028 size_t msize;
1029 int cnt;
1030 int ret;
1031 int target;
1032 unsigned int width;
1033
1034 msize = sizeof (struct MSH_MSG_VerifyAddress) + (nips * sizeof (uint32_t));
1035 msg = GNUNET_malloc (msize);
1036 msg->header.size = htons (msize);
1037 msg->port = htons (listen_port);
1038 msg->nips = htons (nips);
1039 for (cnt = 0; cnt < nips; cnt++)
1040 {
1041 msg->ipaddrs[cnt] = htonl ((uint32_t) s_addrs[cnt]);
1042 }
1043 width = rwidth;
1044 if ( (0 != ( (nproc - 1) % rwidth)) && (current_round == ( (nproc - 1) / rwidth)) )
1045 width = (nproc - 1) % rwidth;
1046 cpys = NULL;
1047 cpys = GNUNET_malloc (msize * width);
1048 sreqs = GNUNET_malloc (width * sizeof (MPI_Request));
1049 for (cnt=0; cnt < width; cnt++)
1050 {
1051 (void) memcpy (&cpys[cnt], msg, msize);
1052 target = (current_round * rwidth) + cnt + 1;
1053 GNUNET_assert (target < nproc);
1054 target = (rank + target) % nproc;
1055 LOG_DEBUG ("%d: Sending message to %d\n", rank, target);
1056 ret = MPI_Isend (&cpys[cnt], msize, MPI_BYTE, target,
1057 MSH_MTYPE_VERIFY_ADDRESSES, MPI_COMM_WORLD, &sreqs[cnt]);
1058 if (MPI_SUCCESS != ret)
1059 break;
1060 }
1061 free (msg);
1062 msg = NULL;
1063 if (cnt != width)
1064 {
1065 for (cnt--; cnt >= 0; cnt--)
1066 {
1067 GNUNET_break (MPI_SUCCESS == MPI_Cancel (&sreqs[cnt]));
1068 GNUNET_break (MPI_SUCCESS == MPI_Wait (&sreqs[cnt], MPI_STATUS_IGNORE));
1069 }
1070 goto err_ret;
1071 }
1072 for (cnt=0; cnt < width; cnt++)
1073 {
1074 GNUNET_break (MPI_SUCCESS == MPI_Wait (&sreqs[cnt], MPI_STATUS_IGNORE));
1075 }
1076 LOG_DEBUG ("%d: Round: %d -- All messages sent successfully\n", rank, current_round);
1077 if (NULL != cpys)
1078 {
1079 free (cpys);
1080 cpys = NULL;
1081 }
1082
1083 err_ret:
1084 GNUNET_free_non_null (cpys);
1085 GNUNET_free_non_null (sreqs);
1086 return (MPI_SUCCESS == ret) ? GNUNET_OK : GNUNET_SYSERR;
1087}
1088
1089
1090/**
1091 * This functions opens a listen socket, sends this instance's IP addresses to
1092 * other instances and receives their IP addresses, starts accepting connections
1093 * on listen socket and verifies the IP addresses of other instances by
1094 * connecting to their listen sockets
1095 *
1096 * @return GNUNET_OK if verification is successful; GNUNET_SYSERR upon error (an error
1097 * message is logged)
1098 */
1099static int
1100run_round_ ()
1101{
1102 unsigned int cnt;
1103
1104 if (GNUNET_SYSERR == send_addresses ())
1105 return GNUNET_SYSERR;
1106 if (NULL == (riainfos = receive_addresses ()))
1107 return GNUNET_SYSERR;
1108 atask = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
1109 listen_socket, &accept_task, NULL);
1110
1111 if (MPI_SUCCESS != MPI_Barrier (MPI_COMM_WORLD))
1112 {
1113 GNUNET_break (0);
1114 return GNUNET_SYSERR;
1115 }
1116 for (cnt = 0; cnt < rwidth; cnt++)
1117 verify_addresses (riainfos[cnt]);
1118 finalise_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
1119 &finalise_round, NULL);
1120 return GNUNET_OK;
1121}
1122
1123
1124/**
1125 * Task for running a round
1126 *
1127 * @param cls NULL
1128 * @param tc scheduler task context
1129 */
1130static void
1131run_round (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1132{
1133 rtask = GNUNET_SCHEDULER_NO_TASK;
1134 if (GNUNET_OK != run_round_ ())
1135 GNUNET_SCHEDULER_shutdown ();
1136}
1137
1138
1139/**
1140 * Function to copy NULL terminated list of arguments
1141 *
1142 * @param argv the NULL terminated list of arguments. Cannot be NULL.
1143 * @return the copied NULL terminated arguments
1144 */
1145static char **
1146copy_argv (char *const *argv)
1147{
1148 char **argv_dup;
1149 unsigned int argp;
1150
1151 GNUNET_assert (NULL != argv);
1152 for (argp = 0; NULL != argv[argp]; argp++) ;
1153 argv_dup = GNUNET_malloc (sizeof (char *) * (argp + 1));
1154 for (argp = 0; NULL != argv[argp]; argp++)
1155 argv_dup[argp] = strdup (argv[argp]);
1156 return argv_dup;
1157}
1158
1159
1160/**
1161 * Frees the given NULL terminated arguments
1162 *
1163 * @param argv the NULL terminated list of arguments
1164 */
1165static void
1166free_argv (char **argv)
1167{
1168 unsigned int argp;
1169
1170 for (argp = 0; NULL != argv[argp]; argp++)
1171 GNUNET_free (argv[argp]);
1172 GNUNET_free (argv);
1173}
1174
1175
1176/**
1177 * Main function that will be run.
1178 *
1179 * @param cls closure
1180 * @param args remaining command-line arguments
1181 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
1182 * @param cfg configuration
1183 */
1184static void
1185run (void *cls, char *const *args, const char *cfgfile,
1186 const struct GNUNET_CONFIGURATION_Handle *cfg)
1187{
1188 struct sockaddr_in addr;
1189 socklen_t addrlen;
1190 unsigned int cnt;
1191
1192 LOG_DEBUG ("Running main task\n");
1193 if (0 == rwidth)
1194 {
1195 LOG_ERROR ("Round width cannot be 0. Exiting\n");
1196 return;
1197 }
1198 if (nproc <= rwidth)
1199 {
1200 LOG_ERROR ("Round width should be less than the number of processes\n");
1201 return;
1202 }
1203 for (cnt = 0; NULL != args[cnt]; cnt++);
1204 if (0 == cnt)
1205 {
1206 LOG_ERROR ("Need a command to execute\n");
1207 return;
1208 }
1209 run_args = copy_argv (args);
1210 bitmap = bitmap_create (rwidth);
1211 addrmap = addressmap_create (nproc);
1212 addrlen = sizeof (struct sockaddr_in);
1213 (void) memset (&addr, 0, addrlen);
1214 addr.sin_addr.s_addr = INADDR_ANY; /* bind to all available addresses */
1215 listen_socket = open_listen_socket ((struct sockaddr *) &addr, addrlen, rwidth);
1216 listen_port = ntohs (addr.sin_port);
1217 if (NULL == listen_socket)
1218 return;
1219 if (0 == listen_port)
1220 {
1221 GNUNET_break (0);
1222 goto clo_ret;
1223 }
1224 LOG_DEBUG ("Listening on port %u\n", listen_port);
1225 GNUNET_OS_network_interfaces_list (&net_if_processor, NULL);
1226 if (0 == nips)
1227 {
1228 LOG_ERROR ("No IP addresses found\n");
1229 return;
1230 }
1231 schedule_next_round ();
1232 shutdown_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
1233 &do_shutdown, NULL);
1234 return;
1235
1236 clo_ret:
1237 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (listen_socket));
1238 listen_socket = NULL;
1239}
1240
1241
1242/**
1243 * The execution start point
1244 *
1245 * @param argc the number of arguments
1246 * @param argv the argument strings
1247 * @return 0 for successful termination; 1 for termination upon error
1248 */
1249int
1250main (int argc, char **argv)
1251{
1252 static const struct GNUNET_GETOPT_CommandLineOption options[] = {
1253 {'w', "round-width", "COUNT",
1254 "set the size of each round to COUNT",
1255 GNUNET_YES, &GNUNET_GETOPT_set_uint, &rwidth},
1256 GNUNET_GETOPT_OPTION_END
1257 };
1258 int ret;
1259
1260 ret = 1;
1261 rwidth = 1;
1262 GNUNET_log_setup ("mshd", NULL, NULL);
1263 if (MPI_SUCCESS != MPI_Init(&argc, &argv))
1264 {
1265 LOG_ERROR ("Failed to initialise MPI\n");
1266 return 1;
1267 }
1268 if (MPI_SUCCESS != MPI_Comm_size (MPI_COMM_WORLD, &nproc))
1269 {
1270 LOG_ERROR ("Cannot determine the number of mshd processes\n");
1271 goto fail;
1272 }
1273 if (nproc <= rwidth)
1274 {
1275 LOG_ERROR ("Given round width is greater than or equal to number of mshd processes\n");
1276 goto fail;
1277 }
1278 if (MPI_SUCCESS != MPI_Comm_rank (MPI_COMM_WORLD, &rank))
1279 {
1280 LOG_ERROR ("Cannot determine our MPI rank\n");
1281 goto fail;
1282 }
1283 if (GNUNET_OK != GNUNET_PROGRAM_run (argc, argv, "mshd", "mshd: MSH daemon",
1284 options, &run, NULL))
1285 {
1286 GNUNET_break (0);
1287 goto fail;
1288 }
1289 ret = 0;
1290
1291 fail:
1292 if (MODE_WORKER <= mode)
1293 return;
1294 LOG_DEBUG ("Returning\n");
1295 GNUNET_break (MPI_SUCCESS == MPI_Finalize());
1296 return ret;
1297}
diff --git a/src/mtypes.h b/src/mtypes.h
new file mode 100644
index 0000000..e699ee9
--- /dev/null
+++ b/src/mtypes.h
@@ -0,0 +1,317 @@
1/**
2 * @file mtypes.h
3 * @brief message formats
4 * @author Sree Harsha Totakura <sreeharsha@totakura.in>
5 */
6
7#ifndef MTYPES_H_
8#define MTYPES_H_
9
10#include "common.h"
11
12
13/**
14 * Message for sending addresses for verification
15 */
16struct MSH_MSG_VerifyAddress
17{
18 /**
19 * Message header
20 */
21 struct GNUNET_MessageHeader header;
22
23 /**
24 * Randomly chosen port number
25 */
26 uint16_t port GNUNET_PACKED;
27
28 /**
29 * Number of IP addresses
30 */
31 uint16_t nips GNUNET_PACKED;
32
33 /**
34 * IPv4 addresses to follow as 32 bit unsigned integeters
35 */
36 uint32_t ipaddrs[0];
37
38#if 0
39 /* Internet address. */
40 typedef uint32_t in_addr_t;
41 struct in_addr
42 {
43 in_addr_t s_addr;
44 };
45 /* Structure describing an Internet socket address. */
46 struct sockaddr_in
47 {
48 __SOCKADDR_COMMON (sin_);
49 in_port_t sin_port; /* Port number. */
50 struct in_addr sin_addr; /* Internet address. */
51
52 /* Pad to size of `struct sockaddr'. */
53 unsigned char sin_zero[sizeof (struct sockaddr) -
54 __SOCKADDR_COMMON_SIZE -
55 sizeof (in_port_t) -
56 sizeof (struct in_addr)];
57 };
58#endif
59};
60
61
62/**
63 * Structure for representing verified addresses of an instance. The type for these
64 * messages should be MSH_MTYPE_INSTANCE_ADDRESS
65 */
66struct MSH_MSG_InstanceAdresses
67{
68 /**
69 * Header for this message
70 */
71 struct GNUNET_MessageHeader header;
72
73 /**
74 * The rank of the instance
75 */
76 uint16_t rank GNUNET_PACKED;
77
78 /**
79 * The port number on which the instance is listening
80 */
81 uint16_t port GNUNET_PACKED;
82
83 /**
84 * The number of addresses
85 */
86 uint16_t nips GNUNET_PACKED;
87
88 /**
89 * IPv4 addresses to follow as 32 bit unsigned integers
90 */
91 uint32_t ipaddrs[0];
92
93};
94
95
96/*********************************************************************
97 * MPI tag numbers for each message type
98 *********************************************************************/
99
100/**
101 * Tag number for address verification messages
102 */
103#define MSH_MTYPE_VERIFY_ADDRESSES 100
104
105/**
106 * Tag number for address messages
107 */
108#define MSH_MTYPE_INSTANCE_ADDRESS 101
109
110/**
111 * Tag number for message signalling that MSHD instances should shutdown
112 */
113#define MSH_MTYPE_SHUTDOWN 102
114
115
116/****************************************************************/
117/* MSH Daemon and MSH command line tool communication messsages */
118/****************************************************************/
119
120#define MSH_MTYPE_RUNCMD 200
121
122#define MSH_MTYPE_CMD_STREAM_STDIN 202
123
124#define MSH_MTYPE_CMD_STREAM_STDOUT 203
125
126#define MSH_MTYPE_ADDRESS_LOOKUP 204
127
128#define MSH_MTYPE_ADDRESS_LOOKUP_REPLY 205
129
130#define MSH_MTYPE_CHALLENGE 206
131
132#define MSH_MTYPE_CHALLENGE_RESPONSE 207
133
134#define MSH_MTYPE_EXEC_BEGIN 208
135
136#define MSH_MTYPE_SESSION_OPEN 209
137
138#define MSH_MTYPE_CMD_STREAM_STDERR 210
139
140
141/***********************/
142/* MSH waiter messages */
143/***********************/
144
145#define MSH_MTYPE_PTY_MODE 300
146
147
148/*********************/
149/* MSH Session types */
150/*********************/
151
152/**
153 * Non interactive session; a pseudo-tty is not created at the server-side
154 */
155#define MSH_SESSION_TYPE_NONINTERACTIVE 0
156
157/**
158 * Interactive session; a pseudo-tty is created at the server-side
159 */
160#define MSH_SESSION_TYPE_INTERACTIVE 1
161
162/**
163 * Message for opening a session
164 */
165struct MSH_MSG_SessionOpen
166{
167 /**
168 * header; set type to MSH_MTYPE_SESSION_OPEN
169 */
170 struct GNUNET_MessageHeader header;
171
172 /**
173 * Type of the session; Must be one of the MSH_MTYPE_SESSION_TYPE_*
174 */
175 uint32_t type GNUNET_PACKED;
176};
177
178
179/**
180 * Message for sending a remote command and its arguments to MSHD
181 */
182struct MSH_MSG_RunCmd
183{
184 /**
185 * header; set type to MSH_MTYPE_RUNCMD
186 */
187 struct GNUNET_MessageHeader header;
188
189 /**
190 * The command and all its arguments to be followed. Each string is to be
191 * NULL-terminated.
192 */
193 char cmd[0];
194};
195
196
197/**
198 * Message indicating the status of the RunCmd message
199 */
200struct MSH_MSG_RunCmdStatus
201{
202 /**
203 * header; set type to MSH_MTYPE_RUNCMDSTATUS
204 */
205 struct GNUNET_MessageHeader header;
206
207 /**
208 * The error message, if any. Absence of error message signifies that the
209 * RunCmd message is accepted and will be forwarded accordingly
210 */
211 char emsg[0];
212};
213
214
215/**
216 * Message for sending STDIN for the remote command to MSHD
217 */
218struct MSH_MSG_CmdIO
219{
220 /**
221 * header; set type to MSH_MTYPE_CMD_STREAM_STDIN or
222 * MSH_MTYPE_CMD_STREAM_STDOUT according to the direction of the stream
223 */
224 struct GNUNET_MessageHeader header;
225
226 /**
227 * stdin data
228 */
229 char data[0];
230};
231
232#define MAX_IO_DATA (GNUNET_SERVER_MAX_MESSAGE_SIZE - sizeof (struct MSH_MSG_CmdIO))
233
234struct MSH_MSG_AddressLookup
235{
236 /**
237 * header; set type to MSH_MTYPE_ADDRESS_LOOKUP
238 */
239 struct GNUNET_MessageHeader header;
240
241 /**
242 * The IP address to lookup
243 */
244 uint32_t ip;
245
246};
247
248
249struct MSH_MSG_AddressLookupReply
250{
251 /**
252 * header; set type to MSH_MTYPE_ADDRESS_LOOKUP_REPLY
253 */
254 struct GNUNET_MessageHeader header;
255
256 /**
257 * the port number. Will be set to 0 upon lookup failure
258 */
259 uint16_t port;
260
261 /**
262 * If the lookup failed, it will contain the related NULL-terminated error
263 * message
264 */
265 char emsg[0];
266};
267
268
269struct MSH_MSG_Challenge
270{
271 /**
272 * header; set type to MSH_MTYPE_CHALLENGE
273 */
274 struct GNUNET_MessageHeader header;
275
276 /**
277 * ascii encoded salt value to follow (0-terminated)
278 */
279 struct GNUNET_CRYPTO_HashAsciiEncoded salt;
280};
281
282
283struct MSH_MSG_ChallengeResponse
284{
285 /**
286 * header; set type to MSH_MTYPE_CHALLENGE_RESPONSE
287 */
288 struct GNUNET_MessageHeader header;
289
290 /**
291 * ascii encoded auth hash
292 */
293 struct GNUNET_CRYPTO_HashAsciiEncoded auth;
294};
295
296
297struct MSH_MSG_PtyMode
298{
299 /**
300 * header; set type to MSH_MTYPE_PTY_MODE
301 */
302 struct GNUNET_MessageHeader header;
303
304 uint16_t ws_row GNUNET_PACKED;
305 uint16_t ws_col GNUNET_PACKED;
306 uint16_t ws_xpixel GNUNET_PACKED;
307 uint16_t ws_ypixel GNUNET_PACKED;
308 uint32_t ospeed GNUNET_PACKED;
309 uint32_t ispeed GNUNET_PACKED;
310 uint16_t nsettings GNUNET_PACKED;
311 /* Followed by nsettings uint16_t = uint16_t. See ttymodes.h for the
312 settings that are to be included */
313 /* Followed by the TERM var string (NULL-terminated) */
314};
315
316
317#endif /* MTYPES_H_ */
diff --git a/src/pmonitor.c b/src/pmonitor.c
new file mode 100644
index 0000000..704eac0
--- /dev/null
+++ b/src/pmonitor.c
@@ -0,0 +1,314 @@
1/**
2 * @file pmonitor.c
3 * @brief process monitoring functions
4 * @author Sree Harsha Totakura <sreeharsha@totakura.in>
5 */
6
7#include "common.h"
8#include "gnunet/gnunet_util_lib.h"
9#include "pmonitor.h"
10
11/**
12 * Generic logging shortcut
13 */
14#define LOG(kind, ...) \
15 GNUNET_log_from (kind, "mshd-pmonitor", __VA_ARGS__)
16
17/**
18 * Debug logging shorthand
19 */
20#define LOG_DEBUG(...) \
21 LOG (GNUNET_ERROR_TYPE_DEBUG, __VA_ARGS__)
22
23
24struct MonitorCtx
25{
26 /**
27 * Termination notification callback
28 */
29 MSH_ProcExitCallback cb;
30
31 /**
32 * closure for the above callback
33 */
34 void *cls;
35};
36
37/**
38 * Task to kill the child
39 */
40static GNUNET_SCHEDULER_TaskIdentifier child_death_task_id;
41
42/**
43 * Pipe used to communicate shutdown via signal.
44 */
45static struct GNUNET_DISK_PipeHandle *sigpipe;
46
47/**
48 * Signal context for SIGCHLD
49 */
50static struct GNUNET_SIGNAL_Context *shc_chld;
51
52/**
53 * hashmap for storing process monitoring context
54 */
55static struct GNUNET_CONTAINER_MultiHashMap32 *map;
56
57
58/**
59 * Task triggered whenever we receive a SIGCHLD (child
60 * process died).
61 *
62 * @param cls closure, NULL if we need to self-restart
63 * @param tc context
64 */
65static void
66child_death_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
67{
68 const struct GNUNET_DISK_FileHandle *pr;
69 struct MonitorCtx *ctx;
70 MSH_ProcExitCallback cb;
71 void *cb_cls;
72 char c[16];
73 enum GNUNET_OS_ProcessStatusType type;
74 int status;
75 pid_t cid;
76 int code;
77
78 cb = NULL;
79 pr = GNUNET_DISK_pipe_handle (sigpipe, GNUNET_DISK_PIPE_END_READ);
80 child_death_task_id = GNUNET_SCHEDULER_NO_TASK;
81 if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_READ_READY))
82 {
83 child_death_task_id =
84 GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
85 pr, &child_death_task, NULL);
86 return;
87 }
88 /* consume the signal */
89 GNUNET_break (0 < GNUNET_DISK_file_read (pr, &c, sizeof (c)));
90 LOG_DEBUG ("Got SIGCHLD\n");
91 cid = waitpid (-1, &status, WNOHANG);
92 if (0 == cid)
93 {
94 LOG_DEBUG ("Child hasn't died. Resuming to monitor its status\n");
95 goto resume;
96 }
97 if (-1 == cid)
98 {
99 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "wait");
100 goto resume;
101 }
102 type = GNUNET_OS_PROCESS_UNKNOWN;
103 if (WIFEXITED (status))
104 {
105 type = GNUNET_OS_PROCESS_EXITED;
106 code = WEXITSTATUS (status);
107 }
108 if (WIFSIGNALED (status))
109 {
110 type = GNUNET_OS_PROCESS_SIGNALED;
111 code = WTERMSIG (status);
112 }
113 if (GNUNET_OS_PROCESS_UNKNOWN == type)
114 {
115 GNUNET_break (0);
116 goto resume;
117 }
118 ctx = GNUNET_CONTAINER_multihashmap32_get (map, (uint32_t) cid);
119 if (NULL == ctx)
120 goto resume;
121 cb = ctx->cb;
122 cb_cls = ctx->cls;
123 GNUNET_CONTAINER_multihashmap32_remove (map, (uint32_t) cid, ctx);
124 GNUNET_free (ctx);
125
126 resume:
127 child_death_task_id =
128 GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
129 pr, &child_death_task, NULL);
130 if (NULL != cb)
131 cb (cb_cls, type, code);
132}
133
134
135/**
136 * Signal handler called for SIGCHLD.
137 */
138static void
139sighandler_child_death ()
140{
141 static char c;
142 int old_errno; /* back-up errno */
143
144 old_errno = errno;
145 GNUNET_break (1 ==
146 GNUNET_DISK_file_write (GNUNET_DISK_pipe_handle
147 (sigpipe, GNUNET_DISK_PIPE_END_WRITE),
148 &c, sizeof (c)));
149 errno = old_errno;
150}
151
152
153/**
154 * Initialise process monitoring subsystem. Registers SIGCHLD signal handler
155 * and the necessary pipe mechanism for reading the signal notification in a
156 * safe way
157 */
158void
159MSH_pmonitor_init ()
160{
161 const struct GNUNET_DISK_FileHandle *pr;
162
163 GNUNET_assert (NULL == sigpipe);
164 GNUNET_assert (NULL == shc_chld);
165 GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == child_death_task_id);
166 GNUNET_assert (NULL != (sigpipe = GNUNET_DISK_pipe (GNUNET_NO, GNUNET_NO,
167 GNUNET_NO, GNUNET_NO)));
168 GNUNET_assert (NULL != (shc_chld = GNUNET_SIGNAL_handler_install
169 (GNUNET_SIGCHLD, &sighandler_child_death)));
170 pr = GNUNET_DISK_pipe_handle (sigpipe, GNUNET_DISK_PIPE_END_READ);
171 map = GNUNET_CONTAINER_multihashmap32_create (10);
172 GNUNET_assert (NULL != map);
173 child_death_task_id =
174 GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
175 pr, &child_death_task, NULL);
176
177}
178
179
180/**
181 * Iterator over hash map entries.
182 *
183 * @param cls closure
184 * @param key current key code
185 * @param value value in the hash map
186 * @return GNUNET_YES if we should continue to
187 * iterate,
188 * GNUNET_NO if not.
189 */
190static int
191cleanup_iterator (void *cls, uint32_t key, void *value)
192{
193 struct MonitorCtx *ctx = value;
194
195 GNUNET_assert (GNUNET_YES ==
196 GNUNET_CONTAINER_multihashmap32_remove (map,
197 key,
198 ctx));
199 GNUNET_free (ctx);
200 return GNUNET_YES;
201}
202
203
204/**
205 * shutdown process monitoring subsystem
206 */
207void
208MSH_pmonitor_shutdown ()
209{
210 /* fixme clear monitoring contexts */
211 GNUNET_assert (NULL != map);
212 GNUNET_break (GNUNET_SYSERR !=
213 GNUNET_CONTAINER_multihashmap32_iterate (map,
214 &cleanup_iterator,
215 NULL));
216 GNUNET_CONTAINER_multihashmap32_destroy (map);
217 map = NULL;
218 GNUNET_assert (NULL != sigpipe);
219 GNUNET_assert (NULL != shc_chld);
220 if (GNUNET_SCHEDULER_NO_TASK != child_death_task_id)
221 {
222 GNUNET_SCHEDULER_cancel (child_death_task_id);
223 child_death_task_id = GNUNET_SCHEDULER_NO_TASK;
224 }
225 GNUNET_SIGNAL_handler_uninstall (shc_chld);
226 shc_chld = NULL;
227 GNUNET_DISK_pipe_close (sigpipe);
228 sigpipe = NULL;
229}
230
231
232/**
233 * Monitors a process for its termination.
234 *
235 * @param proc the process to monitor for termination
236 * @param cb the callback to be called for notifying the termination of the
237 * process
238 * @param cls the closure for the above callback
239 */
240void
241MSH_monitor_process_pid (pid_t pid,
242 MSH_ProcExitCallback cb, void *cls)
243{
244 struct MonitorCtx *ctx;
245
246 GNUNET_assert (NULL != map);
247 ctx = GNUNET_malloc (sizeof (struct MonitorCtx));
248 ctx->cb = cb;
249 ctx->cls = cls;
250 GNUNET_assert
251 (GNUNET_OK ==
252 GNUNET_CONTAINER_multihashmap32_put (map, (uint32_t) pid, ctx,
253 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
254}
255
256
257/**
258 * Monitors a process for its termination.
259 *
260 * @param proc the process to monitor for termination
261 * @param cb the callback to be called for notifying the termination of the
262 * process
263 * @param cls the closure for the above callback
264 */
265void
266MSH_monitor_process (struct GNUNET_OS_Process *proc,
267 MSH_ProcExitCallback cb, void *cls)
268{
269 pid_t pid;
270
271 pid = GNUNET_OS_process_get_pid (proc);
272 MSH_monitor_process_pid (pid, cb, cls);
273}
274
275
276/**
277 * Stop monitoring a process
278 *
279 * @param proc
280 * @return GNUNET_OK upon success; GNUNET_SYSERR if the process is not being
281 * monitored earlier
282 */
283int
284MSH_monitor_process_pid_cancel (pid_t pid)
285{
286 struct MonitorCtx *ctx;
287
288 GNUNET_assert (NULL != map);
289 ctx = GNUNET_CONTAINER_multihashmap32_get (map, (uint32_t) pid);
290 if (NULL == ctx)
291 return GNUNET_SYSERR;
292 GNUNET_assert (GNUNET_YES ==
293 GNUNET_CONTAINER_multihashmap32_remove
294 (map, (uint32_t) pid, ctx));
295 GNUNET_free (ctx);
296 return GNUNET_OK;
297}
298
299
300/**
301 * Stop monitoring a process
302 *
303 * @param proc
304 * @return GNUNET_OK upon success; GNUNET_SYSERR if the process is not being
305 * monitored earlier
306 */
307int
308MSH_monitor_process_cancel (struct GNUNET_OS_Process *proc)
309{
310 pid_t pid;
311
312 pid = GNUNET_OS_process_get_pid (proc);
313 return MSH_monitor_process_pid_cancel (pid);
314}
diff --git a/src/pmonitor.h b/src/pmonitor.h
new file mode 100644
index 0000000..0bdd69d
--- /dev/null
+++ b/src/pmonitor.h
@@ -0,0 +1,90 @@
1/**
2 * @file pmonitor.h
3 * @brief interface for process monitoring functions
4 * @author Sree Harsha Totakura <sreeharsha@totakura.in>
5 */
6
7#ifndef MSHD_PMONITOR_H_
8#define MSHD_PMONITOR_H_
9
10#include <gnunet/gnunet_os_lib.h>
11
12/**
13 * Initialise process monitoring subsystem. Registers SIGCHLD signal handler
14 * and the necessary pipe mechanism for reading the signal notification in a
15 * safe way
16 */
17void
18MSH_pmonitor_init ();
19
20
21/**
22 * shutdown process monitoring subsystem
23 */
24void
25MSH_pmonitor_shutdown ();
26
27
28/**
29 * Callbacks of this type can be supplied to MSH_monitor_process() to be
30 * notified when the corresponding processes exits.
31 *
32 * @param cls the closure passed to MSH_monitor_process()
33 * @param type the process status type
34 * @param long the return/exit code of the process
35 */
36typedef void (*MSH_ProcExitCallback) (void *cls,
37 enum GNUNET_OS_ProcessStatusType type,
38 int code);
39
40
41/**
42 * Monitors a process for its termination.
43 *
44 * @param proc the process to monitor for termination
45 * @param cb the callback to be called for notifying the termination of the
46 * process
47 * @param cls the closure for the above callback
48 */
49void
50MSH_monitor_process (struct GNUNET_OS_Process *proc,
51 MSH_ProcExitCallback cb, void *cls);
52
53
54/**
55 * Stop monitoring a process
56 *
57 * @param proc
58 * @return GNUNET_OK upon success; GNUNET_SYSERR if the process is not being
59 * monitored earlier
60 */
61int
62MSH_monitor_process_cancel (struct GNUNET_OS_Process *proc);
63
64
65/**
66 * Monitors a process for its termination.
67 *
68 * @param proc the process to monitor for termination
69 * @param cb the callback to be called for notifying the termination of the
70 * process
71 * @param cls the closure for the above callback
72 */
73void
74MSH_monitor_process_pid (pid_t pid,
75 MSH_ProcExitCallback cb, void *cls);
76
77
78/**
79 * Stop monitoring a process
80 *
81 * @param proc
82 * @return GNUNET_OK upon success; GNUNET_SYSERR if the process is not being
83 * monitored earlier
84 */
85int
86MSH_monitor_process_pid_cancel (pid_t pid);
87
88#endif /* MSHD_PMONITOR_H_ */
89
90/* End of pmonitor.h */
diff --git a/src/prop.c b/src/prop.c
new file mode 100644
index 0000000..0bf993f
--- /dev/null
+++ b/src/prop.c
@@ -0,0 +1,17 @@
1#include "common.h"
2#include <gnunet/gnunet_util_lib.h>
3
4int main ()
5{
6 char buf[256];
7
8 //GNUNET_log_setup ("msh-prop", NULL, NULL);
9 if (NULL == fgets (buf, sizeof (buf) -1, stdin))
10 {
11 printf ("Input stream closed\n");
12 return 0;
13 }
14 buf[255] = '\0';
15 printf ("%s", buf);
16 return 0;
17}
diff --git a/src/reduce.c b/src/reduce.c
new file mode 100644
index 0000000..6310b96
--- /dev/null
+++ b/src/reduce.c
@@ -0,0 +1,121 @@
1/**
2 * @file reduce.c
3 * @brief functionality for the reduction operations
4 * @author Sree Harsha Totakura <sreeharsha@totakura.in>
5 */
6
7#include "common.h"
8#include <gnunet/gnunet_util_lib.h>
9#include <mpi.h>
10#include "addressmap.h"
11#include "mshd.h"
12#include "mtypes.h"
13
14#define LOG(kind,...) \
15 GNUNET_log_from (kind, "mshd-reduce", __VA_ARGS__)
16
17#define LOG_DEBUG(...) LOG(GNUNET_ERROR_TYPE_DEBUG, __VA_ARGS__)
18
19#define LOG_ERROR(...) LOG(GNUNET_ERROR_TYPE_ERROR, __VA_ARGS__)
20
21
22/**
23 * Perform an ntree reduction on address maps
24 *
25 * @return GNUNET_OK upon success; GNUNET_SYSERR upon failure
26 */
27int
28reduce_ntree ()
29{
30 struct MSH_MSG_InstanceAdresses **iaddr_msgs;
31 char *buf;
32 int nmsg;
33 unsigned int cnt;
34 unsigned int grow;
35 unsigned int size;
36 unsigned int preamble[2]; /* 0: total size; 1: n messages */
37 unsigned int nr;
38
39 for (cnt = 0; cnt < nproc; cnt++)
40 {
41 buf = NULL;
42 size = 0;
43 grow = 0;
44 preamble[0] = 0;
45 preamble[1] = 0;
46 iaddr_msgs = NULL;
47 if (rank == cnt)
48 {
49 if (GNUNET_SYSERR == (nmsg = addressmap_pack (addrmap, &iaddr_msgs)))
50 {
51 GNUNET_break (0);
52 return GNUNET_SYSERR;
53 }
54 for (nr = 0; nr < nmsg; nr++)
55 {
56 grow = ntohs (iaddr_msgs[nr]->header.size);
57 buf = GNUNET_realloc (buf, size + grow);
58 (void) memcpy (buf + size, iaddr_msgs[nr], grow);
59 size += grow;
60 }
61 preamble[0] = size;
62 preamble[1] = nmsg;
63 LOG_DEBUG ("Broadcasting address map from instance %u\n", cnt);
64 }
65 if (MPI_SUCCESS != MPI_Bcast (preamble, 2, MPI_UNSIGNED, cnt, MPI_COMM_WORLD))
66 {
67 GNUNET_break (0);
68 return GNUNET_SYSERR;
69 }
70 if (rank != cnt)
71 {
72 size = preamble[0];
73 nmsg = preamble[1];
74 buf = GNUNET_malloc (size);
75 }
76 GNUNET_assert (NULL != buf);
77 GNUNET_assert (0 < size);
78 if (MPI_SUCCESS != MPI_Bcast (buf, size, MPI_BYTE, cnt, MPI_COMM_WORLD))
79 {
80 GNUNET_break (0);
81 return GNUNET_SYSERR;
82 }
83 if (rank == cnt)
84 {
85 GNUNET_free (buf);
86 for (nr = 0; nr < nmsg; nr++)
87 GNUNET_free (iaddr_msgs[nr]);
88 GNUNET_free (iaddr_msgs);
89 continue;
90 }
91
92 iaddr_msgs = GNUNET_malloc (sizeof (struct MSH_MSG_InstanceAdresses *) *
93 nmsg);
94 grow = 0;
95 for (nr = 0; nr < nmsg; nr++)
96 {
97 iaddr_msgs[nr] = (struct MSH_MSG_InstanceAdresses *) (buf + grow);
98 grow += ntohs (iaddr_msgs[nr]->header.size);
99 if (0 >= addressmap_intersect_msg (addrmap, iaddr_msgs[nr]))
100 {
101 LOG_ERROR ("No common address found for instance %u\n",
102 ntohs (iaddr_msgs[nr]->rank));
103 break;
104 }
105 }
106 GNUNET_free (buf);
107 GNUNET_free (iaddr_msgs);
108 if (nr == nmsg)
109 LOG_DEBUG ("Intersected received addressmap from instance %u\n", cnt);
110 else
111 return GNUNET_SYSERR;
112 }
113 GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_NONCE, &shash);
114 if (MPI_SUCCESS != MPI_Bcast (&shash, sizeof (struct GNUNET_HashCode),
115 MPI_BYTE, 0, MPI_COMM_WORLD))
116 {
117 GNUNET_break (0);
118 return GNUNET_SYSERR;
119 }
120 return GNUNET_OK;
121}
diff --git a/src/reduce.h b/src/reduce.h
new file mode 100644
index 0000000..6545676
--- /dev/null
+++ b/src/reduce.h
@@ -0,0 +1,21 @@
1/**
2 * @file reduce.h
3 * @brief interface for the reduction operations
4 * @author Sree Harsha Totakura <sreeharsha@totakura.in>
5 */
6
7#ifndef REDUCE_H_
8#define REDUCE_H_
9
10#include "common.h"
11
12/**
13 * Perform an ntree reduction on address maps
14 *
15 * @return MSH_OK upon success; MSH_SYSERR upon failure
16 */
17int
18reduce_ntree ();
19
20#endif /* REDUCE_H_ */
21/* End of reduce.h */
diff --git a/src/run.sh b/src/run.sh
new file mode 100755
index 0000000..f8c1238
--- /dev/null
+++ b/src/run.sh
@@ -0,0 +1,6 @@
1#!/bin/sh
2
3echo "Running bash on" $(hostname)
4#xterm
5bash
6
diff --git a/src/server.c b/src/server.c
new file mode 100644
index 0000000..e11f12d
--- /dev/null
+++ b/src/server.c
@@ -0,0 +1,1248 @@
1/**
2 * @file server.c
3 * @brief functions implementing server functionalities of MSH daemon. We
4 * listen for commands from locally started MSH instances and also for
5 * executing commands given by remote MSH daemons.
6 * @author Sree Harsha Totakura <sreeharsha@totakura.in>
7 */
8
9#include "common.h"
10#include <gnunet/gnunet_util_lib.h>
11#include <termios.h>
12#include "mshd.h"
13#include "addressmap.h"
14#include "pmonitor.h"
15#include "util.h"
16
17#define TIMEOUT_SECS(s) \
18 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, s)
19
20#define LOG(kind,...) \
21 GNUNET_log_from (kind, "mshd-server", __VA_ARGS__)
22
23#define LOG_DEBUG(...) LOG(GNUNET_ERROR_TYPE_DEBUG, __VA_ARGS__)
24
25#define LOG_ERROR(...) LOG(GNUNET_ERROR_TYPE_ERROR, __VA_ARGS__)
26
27#define LOG_STRERROR(kind,cmd) \
28 GNUNET_log_from_strerror (kind, "mshd-server", cmd)
29
30/**
31 * server handle for accepting requests from local MSH instances
32 */
33static struct GNUNET_SERVER_Handle *local_serv;
34
35/**
36 * server handle for acceptiong requests from remote MSHD instances
37 */
38static struct GNUNET_SERVER_Handle *daemon_serv;
39
40/**
41 * Notification queue for the local server
42 */
43static struct GNUNET_SERVER_NotificationContext *local_serv_nc;
44
45/**
46 * Notification queue for the daemon server
47 */
48static struct GNUNET_SERVER_NotificationContext *daemon_serv_nc;
49
50/**
51 * Our UID. We use this for access checks
52 */
53uid_t our_uid;
54
55/**
56 * Our GID. We use this for access checks
57 */
58uid_t our_gid;
59
60
61/**
62 * Context for connections requiring to execute commands
63 */
64struct ExecCtx
65{
66 /**
67 * The client handle this context is associated with
68 */
69 struct GNUNET_SERVER_Client *client;
70
71 /**
72 * The command strings to execute
73 */
74 char **args;
75
76 /**
77 * file handle for processes input
78 */
79 struct GNUNET_DISK_FileHandle *fin;
80
81 /**
82 * file handle for processes output
83 */
84 struct GNUNET_DISK_FileHandle *fout;
85
86 /**
87 * file handle for processes output
88 */
89 struct GNUNET_DISK_FileHandle *ferr;
90
91 /**
92 * input buffer. Data from this buffer is written to proc's STDIN when it is
93 * available for writing.
94 */
95 char *buf;
96
97 /**
98 * If this session were to be interactive, the message containing the setting
99 * to use for the pseudo-tty we create
100 */
101 struct MSH_MSG_PtyMode *pty_mode;
102
103 /**
104 * The size of the input buffer
105 */
106 size_t bufsize;
107
108 /**
109 * salt hash used for authentication
110 */
111 struct GNUNET_HashCode salt;
112
113 /**
114 * timeout task
115 */
116 GNUNET_SCHEDULER_TaskIdentifier timeout_task;
117
118 /**
119 * task to read the output from the process
120 */
121 GNUNET_SCHEDULER_TaskIdentifier fout_task;
122
123 /**
124 * task to read the error output from the process
125 */
126 GNUNET_SCHEDULER_TaskIdentifier ferr_task;
127
128 /**
129 * task to write data received from the client to proc's STDIN
130 */
131 GNUNET_SCHEDULER_TaskIdentifier fin_task;
132
133 /**
134 * The pid of the child we start
135 */
136 pid_t child_pid;
137
138 /**
139 * If this is an interactive session, this is the master side of the
140 * pseudo-tty we create
141 */
142 int master;
143
144 /**
145 * Is this an interactive session?
146 */
147 int interactive;
148
149 /**
150 * Is this session authentication?
151 */
152 int authenticated;
153
154 /**
155 * If this is an interactive session, is the pseudo-tty opened?
156 */
157 int pty_opened;
158};
159
160/*
161 * Converts a numeric baud rate to a POSIX speed_t.
162 */
163speed_t
164baud_to_speed(int baud);
165
166
167/**
168 * Destroys an execution context
169 *
170 * @param ctx execution context
171 */
172static void
173destroy_exec_ctx (struct ExecCtx *ctx)
174{
175 unsigned int cnt;
176
177 GNUNET_SERVER_client_drop (ctx->client);
178 if (NULL != ctx->args)
179 {
180 for (cnt = 0; NULL != ctx->args[cnt]; cnt++)
181 GNUNET_free (ctx->args[cnt]);
182 GNUNET_free (ctx->args);
183 }
184 if (0 != ctx->child_pid)
185 {
186 MSH_monitor_process_pid_cancel (ctx->child_pid);
187 GNUNET_break (0 == kill (ctx->child_pid, SIGTERM));
188 }
189 GNUNET_DISK_file_close (ctx->fin);
190 GNUNET_DISK_file_close (ctx->fout);
191 if (NULL != ctx->ferr)
192 GNUNET_DISK_file_close (ctx->ferr);
193 if (GNUNET_SCHEDULER_NO_TASK != ctx->timeout_task)
194 GNUNET_SCHEDULER_cancel (ctx->timeout_task);
195 if (GNUNET_SCHEDULER_NO_TASK != ctx->fout_task)
196 GNUNET_SCHEDULER_cancel (ctx->fout_task);
197 if (GNUNET_SCHEDULER_NO_TASK != ctx->ferr_task)
198 GNUNET_SCHEDULER_cancel (ctx->ferr_task);
199 if (NULL != ctx->buf)
200 GNUNET_free (ctx->buf);
201 GNUNET_free_non_null (ctx->pty_mode);
202 GNUNET_free (ctx);
203}
204
205
206/**
207 * Parse contingious 0-terminated strings from a buffer of given length
208 *
209 * @param buf the buffer
210 * @param size the size of the buffer
211 * @param s will contain the array of strings upon return
212 * @return the number of strings returned in the array
213 */
214static int
215parse_strings (const char *buf, size_t size, char ***s)
216{
217 const char *p;
218 char **strs;
219 size_t off;
220 unsigned int cnt;
221
222 cnt = 0;
223 strs = NULL;
224 p = NULL;
225 for (off = 0; off < size; off++)
226 {
227 if ('\0' == buf[off])
228 {
229 if (NULL == p)
230 continue;
231 GNUNET_array_append (strs, cnt, GNUNET_strdup (p));
232 p = NULL;
233 continue;
234 }
235 if (NULL != p)
236 continue;
237 p = &buf[off];
238 }
239 if (0 < cnt)
240 GNUNET_array_append (strs, cnt, NULL);
241 *s = strs;
242 return cnt;
243}
244
245
246/**
247 * Create a challenge message
248 *
249 * @param ctx the execution context
250 * @return the challenge message
251 */
252static struct GNUNET_MessageHeader *
253create_challenge_message (struct ExecCtx *ctx)
254{
255 struct MSH_MSG_Challenge *msg;
256 uint16_t size;
257
258 GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_NONCE, &ctx->salt);
259 size = sizeof (struct MSH_MSG_Challenge);
260 msg = GNUNET_malloc (size);
261 msg->header.type = htons (MSH_MTYPE_CHALLENGE);
262 msg->header.size = htons (size);
263 GNUNET_CRYPTO_hash_to_enc (&ctx->salt, &msg->salt);
264 LOG_DEBUG ("Challenge nonce: %104s\n", msg->salt.encoding);
265 return &msg->header;
266}
267
268
269/**
270 * Functions with this signature are called whenever a message is
271 * received.
272 *
273 * @param cls closure
274 * @param client identification of the client
275 * @param message the actual message
276 */
277static void
278handle_addresslookup (void *cls, struct GNUNET_SERVER_Client *client,
279 const struct GNUNET_MessageHeader* message)
280{
281 const struct MSH_MSG_AddressLookup *msg;
282 struct MSH_MSG_AddressLookupReply *reply;
283 struct InstanceAddr *iaddr;
284 char *emsg;
285 in_addr_t ip;
286 uint16_t port;
287 uint16_t reply_size;
288
289 emsg = NULL;
290 port = 0;
291 msg = (const struct MSH_MSG_AddressLookup *) message;
292 ip = ntohl (msg->ip);
293 if (GNUNET_NO == reversemap_check (rmap, ip))
294 {
295 emsg = "Given IP address not present in the current mapping\n";
296 goto respond;
297 }
298 iaddr = reversemap_lookup (rmap, ip);
299 GNUNET_assert (NULL != iaddr);
300 port = instance_address_port (iaddr);
301 LOG_DEBUG ("Received ADDRESS_LOOKUP message for IP: %s and port %u\n",
302 ip2str (ip), port);
303 respond:
304 reply_size = sizeof (struct MSH_MSG_AddressLookupReply);
305 if (NULL != emsg)
306 reply_size += strlen (emsg) + 1;
307 reply = GNUNET_malloc (reply_size);
308 reply->header.size = htons (reply_size);
309 reply->header.type = htons (MSH_MTYPE_ADDRESS_LOOKUP_REPLY);
310 reply->port = htons (port);
311 if (NULL != emsg)
312 (void) strcpy (reply->emsg, emsg);
313 GNUNET_SERVER_notification_context_unicast (local_serv_nc, client,
314 &reply->header, GNUNET_NO);
315 GNUNET_SERVER_receive_done (client, GNUNET_OK);
316}
317
318
319/**
320 * Generate the credential for the given challenge
321 *
322 * @param c the challenge
323 * @param cred output parameter for the credential
324 */
325static void
326auth_challenge_cred (struct GNUNET_HashCode *c, struct GNUNET_HashCode *cred)
327{
328 struct GNUNET_HashCode xor;
329
330 GNUNET_CRYPTO_hash_xor (c, &shash, &xor);
331 GNUNET_CRYPTO_hash (&xor, sizeof (struct GNUNET_HashCode), cred);
332}
333
334
335/**
336 * Functions with this signature are called whenever a message is
337 * received.
338 *
339 * @param cls closure
340 * @param client identification of the client
341 * @param message the actual message
342 */
343static void
344handle_auth_challenge (void *cls, struct GNUNET_SERVER_Client *client,
345 const struct GNUNET_MessageHeader* message)
346{
347 const struct MSH_MSG_Challenge *msg;
348 struct MSH_MSG_ChallengeResponse *reply;
349 struct GNUNET_HashCode salt;
350 struct GNUNET_HashCode cred;
351
352 msg = (const struct MSH_MSG_Challenge *) message;
353 LOG_DEBUG ("Challenge nonce: %104s\n", msg->salt.encoding);
354 GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_hash_from_string
355 ((const char *) msg->salt.encoding, &salt));
356 auth_challenge_cred (&salt, &cred);
357 reply = GNUNET_malloc (sizeof (struct MSH_MSG_ChallengeResponse));
358 reply->header.size = htons (sizeof (struct MSH_MSG_ChallengeResponse));
359 reply->header.type = htons (MSH_MTYPE_CHALLENGE_RESPONSE);
360 GNUNET_CRYPTO_hash_to_enc (&cred, &reply->auth);
361 GNUNET_SERVER_notification_context_unicast (local_serv_nc, client,
362 &reply->header, GNUNET_NO);
363 GNUNET_SERVER_receive_done (client, GNUNET_OK);
364}
365
366
367/**
368 * Function to call for access control checks.
369 *
370 * @param cls closure
371 * @param ucred credentials, if available, otherwise NULL
372 * @param addr address
373 * @param addrlen length of address
374 * @return GNUNET_YES to allow, GNUNET_NO to deny, GNUNET_SYSERR
375 * for unknown address family (will be denied).
376 */
377static int
378check_local_access (void *cls,
379 const struct GNUNET_CONNECTION_Credentials *cred,
380 const struct sockaddr * addr, socklen_t addrlen)
381{
382 if ((our_uid != cred->uid) && (our_gid != cred->gid))
383 return GNUNET_NO;
384 return GNUNET_YES;
385}
386
387
388/**
389 * Callback to be called when ever a client connects to the local server
390 *
391 * @param cls NULL
392 * @param client the client handle
393 */
394static void
395local_server_connect (void *cls, struct GNUNET_SERVER_Client *client)
396{
397 if (NULL == client) /* Server shutting down */
398 return;
399 LOG_DEBUG ("A client has been connected locally\n");
400 GNUNET_SERVER_notification_context_add (local_serv_nc, client);
401}
402
403
404/**
405 * Initialise the local server
406 *
407 * @param unixpath the name to use while opening the abstract UNIX domain socket
408 * for listening
409 * @return GNUNET_OK upon success; GNUNET_SYSERR upon failure
410 */
411int
412init_local_server (const char *unixpath)
413{
414 struct sockaddr_un saddr;
415 static const struct GNUNET_SERVER_MessageHandler handlers[] = {
416 {&handle_addresslookup, NULL, MSH_MTYPE_ADDRESS_LOOKUP, sizeof (struct
417 MSH_MSG_AddressLookup)},
418 {&handle_auth_challenge, NULL, MSH_MTYPE_CHALLENGE, sizeof (struct MSH_MSG_Challenge)},
419 {NULL, NULL, 0, 0}
420 };
421 struct sockaddr *saddrs[] = {
422 ((struct sockaddr *) &saddr),
423 NULL
424 };
425 socklen_t saddr_lens[] = {
426 sizeof (struct sockaddr_un),
427 0
428 };
429
430 our_uid = getuid ();
431 our_gid = getgid ();
432 saddr.sun_family = AF_UNIX;
433 (void) memset (saddr.sun_path, 0, sizeof (saddr.sun_path));
434 (void) strncpy (saddr.sun_path, unixpath, sizeof (saddr.sun_path) - 1);
435 saddr.sun_path[0] = '\0'; /* use abstract sockets */
436 local_serv = GNUNET_SERVER_create (&check_local_access, NULL,
437 saddrs,
438 saddr_lens,
439 GNUNET_TIME_UNIT_FOREVER_REL,
440 GNUNET_YES);
441 if (NULL == local_serv)
442 {
443 GNUNET_break (0);
444 return GNUNET_SYSERR;
445 }
446 GNUNET_SERVER_add_handlers (local_serv, handlers);
447 GNUNET_SERVER_connect_notify (local_serv, &local_server_connect, NULL);
448 local_serv_nc = GNUNET_SERVER_notification_context_create (local_serv, 1);
449 return GNUNET_OK;
450}
451
452
453/**
454 * Shutdown the local server
455 */
456void
457shutdown_local_server ()
458{
459 LOG_DEBUG ("Shutting down address lookup server\n");
460 if (NULL != local_serv)
461 {
462 GNUNET_SERVER_destroy (local_serv);
463 local_serv = NULL;
464 }
465}
466
467
468/******************************************************************************/
469/* Daemon server. Responsbile for executing commands submitted by remote MSH */
470/* clients */
471/******************************************************************************/
472
473
474/**
475 * Handle session open message and start challenge authentication.
476 *
477 * @param cls closure
478 * @param client identification of the client
479 * @param message the actual message
480 */
481static void
482handle_session_open (void *cls,
483 struct GNUNET_SERVER_Client *client,
484 const struct GNUNET_MessageHeader* message)
485{
486 struct ExecCtx *exec_ctx;
487 const struct MSH_MSG_SessionOpen *msg;
488 struct GNUNET_MessageHeader *reply;
489
490 LOG_DEBUG ("Received a SESSION_OPEN message\n");
491 exec_ctx = GNUNET_SERVER_client_get_user_context (client, struct ExecCtx);
492 GNUNET_assert (NULL != exec_ctx);
493 msg = (const struct MSH_MSG_SessionOpen *) message;
494 if (NULL != exec_ctx->args)
495 {
496 GNUNET_break (0);
497 goto close_conn;
498 }
499 if (MSH_SESSION_TYPE_INTERACTIVE == ntohl (msg->type))
500 exec_ctx->interactive = GNUNET_YES;
501 reply = create_challenge_message (exec_ctx);
502 LOG_DEBUG ("Sending AUTH_CHALLENGE\n");
503 GNUNET_SERVER_notification_context_unicast (daemon_serv_nc, client, reply,
504 GNUNET_NO);
505 GNUNET_SERVER_receive_done (client, GNUNET_OK);
506 return;
507
508 close_conn:
509 GNUNET_break_op (0);
510 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
511}
512
513
514/**
515 * Function to read from the given stream and write to the given client
516 *
517 * @param fd the file handler for the stream to redirect to the client
518 * @param client the client to send to
519 * @param mtype the type denoting the stream (STDOUT/STDERR) of the fd
520 * @return GNUNET_OK upon success; GNUNET_SYSERR upon error
521 */
522static int
523redirect_stream (struct GNUNET_DISK_FileHandle *fd,
524 struct GNUNET_SERVER_Client *client,
525 uint16_t mtype)
526{
527
528 struct MSH_MSG_CmdIO *msg;
529 static char data[MAX_IO_DATA];
530 ssize_t size;
531 uint16_t msize;
532
533 errno = 0;
534 size = GNUNET_DISK_file_read_non_blocking (fd, data, MAX_IO_DATA);
535 if (size <= 0)
536 return GNUNET_SYSERR;
537 msize = size + sizeof (struct MSH_MSG_CmdIO);
538 msg = GNUNET_malloc (msize);
539 msg->header.type = htons (mtype);
540 msg->header.size = htons (msize);
541 memcpy (msg->data, data, size);
542 GNUNET_SERVER_notification_context_unicast (daemon_serv_nc, client,
543 &msg->header, GNUNET_NO);
544 return GNUNET_OK;
545}
546
547
548/**
549 * Task to read the output from a process and send it to client
550 *
551 * @param cls the client context
552 * @param tc scheduler task context
553 */
554static void
555read_fout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
556{
557 struct ExecCtx *exec_ctx = cls;
558
559 exec_ctx->fout_task = GNUNET_SCHEDULER_NO_TASK;
560 if (0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason))
561 return;
562 if (GNUNET_SYSERR == redirect_stream (exec_ctx->fout,
563 exec_ctx->client,
564 MSH_MTYPE_CMD_STREAM_STDOUT))
565 {
566 if (GNUNET_SCHEDULER_NO_TASK == exec_ctx->ferr_task)
567 GNUNET_SERVER_client_disconnect (exec_ctx->client);
568 return;
569 }
570 exec_ctx->fout_task =
571 GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
572 exec_ctx->fout, &read_fout, exec_ctx);
573}
574
575
576/**
577 * Task to read the output from a process and send it to client
578 *
579 * @param cls the client context
580 * @param tc scheduler task context
581 */
582static void
583read_ferr (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
584{
585 struct ExecCtx *exec_ctx = cls;
586
587 exec_ctx->ferr_task = GNUNET_SCHEDULER_NO_TASK;
588 if (0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason))
589 return;
590 if (GNUNET_SYSERR == redirect_stream (exec_ctx->ferr,
591 exec_ctx->client,
592 MSH_MTYPE_CMD_STREAM_STDERR))
593 {
594 if (GNUNET_SCHEDULER_NO_TASK == exec_ctx->fout_task)
595 GNUNET_SERVER_client_disconnect (exec_ctx->client);
596 return;
597 }
598 exec_ctx->ferr_task =
599 GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
600 exec_ctx->ferr, &read_ferr, exec_ctx);
601}
602
603
604/**
605 * Configure the terminal for the child
606 */
607static int
608parse_term_mode (const struct MSH_MSG_PtyMode *msg,
609 struct termios *tio,
610 struct winsize *ws,
611 char **termstr)
612{
613 uint16_t *params;
614 char *str;
615 unsigned int cnt;
616 unsigned int ns;
617 uint16_t msize;
618 size_t expected;
619 speed_t ospeed;
620 speed_t ispeed;
621
622 msize = ntohs (msg->header.size);
623 ns = ntohs (msg->nsettings);
624 expected = (sizeof (struct MSH_MSG_PtyMode) + (sizeof (uint16_t) * ns * 2));
625 if (msize < expected)
626 {
627 GNUNET_break (0);
628 return GNUNET_SYSERR;
629 }
630#define PARSE_WIN_SIZE(field) \
631 ws->field = ntohs (msg->field);
632 PARSE_WIN_SIZE (ws_row);
633 PARSE_WIN_SIZE (ws_col);
634 PARSE_WIN_SIZE (ws_xpixel);
635 PARSE_WIN_SIZE (ws_ypixel);
636#undef PARSE_WIN_SIZE
637 ospeed = baud_to_speed (ntohl (msg->ospeed));
638 ispeed = baud_to_speed (ntohl (msg->ispeed));
639 if (0 != cfsetospeed (tio, ospeed))
640 {
641 GNUNET_break (0);
642 return GNUNET_SYSERR;
643 }
644 if (0 != cfsetispeed (tio, ispeed))
645 {
646 GNUNET_break (0);
647 return GNUNET_SYSERR;
648 }
649 params = (uint16_t *) &msg[1];
650 for (cnt = 0; cnt < ns; cnt++)
651 {
652 switch (ntohs (params[2 * cnt]))
653 {
654#define TTYCHAR(NAME,OP) \
655 case OP: \
656 tio->c_cc[NAME] = ntohs (params[(2 * cnt)+1]); \
657 break;
658#define TTYMODE(NAME, FIELD, OP) \
659 case OP: \
660 if (1 == ntohs (params[(2 * cnt)+1])) \
661 tio->FIELD |= NAME; \
662 break;
663#include "ttymodes.h"
664#undef TTYCHAR
665#undef TTYMODE
666
667 default:
668 GNUNET_assert (0);
669 }
670 }
671 if (0 == (msize - expected))
672 return GNUNET_OK;
673 str = ((void *) msg) + expected;
674 if ('\0' != str[(msize - expected) - 1])
675 {
676 GNUNET_break (0);
677 str = NULL;
678 return GNUNET_OK;
679 }
680 *termstr = GNUNET_strdup (str);
681 return GNUNET_OK;
682}
683
684
685/**
686 * Callback that will be called when a child processes terminates. The
687 * associated client context for the client which requested this process will be
688 * destroyed
689 *
690 * @param cls the closure passed to MSH_monitor_process()
691 * @param type the process status type
692 * @param long the return/exit code of the process
693 */
694static void
695proc_exit_cb (void *cls, enum GNUNET_OS_ProcessStatusType type, int code)
696{
697 struct ExecCtx *exec_ctx = cls;
698
699 LOG_DEBUG ("Command `%s' exited.\n", exec_ctx->args[0]);
700 exec_ctx->child_pid = 0;
701 GNUNET_SCHEDULER_cancel (exec_ctx->fout_task);
702 exec_ctx->fout_task = GNUNET_SCHEDULER_add_now (&read_fout, exec_ctx);
703 if (GNUNET_SCHEDULER_NO_TASK != exec_ctx->ferr_task)
704 {
705 GNUNET_SCHEDULER_cancel (exec_ctx->ferr_task);
706 exec_ctx->ferr_task = GNUNET_SCHEDULER_add_now (&read_ferr, exec_ctx);
707 }
708}
709
710
711/**
712 * start the process from the execution process
713 *
714 * @param ctx the execution context
715 * @return GNUNET_OK upon success; GNUNET_SYSERR upon failure
716 */
717static int
718proc_exec (struct ExecCtx *ctx)
719{
720 struct GNUNET_DISK_PipeHandle *pin;
721 struct GNUNET_DISK_PipeHandle *pout;
722 struct GNUNET_DISK_PipeHandle *perr;
723 struct GNUNET_OS_Process *proc;
724 char *fnpty;
725 char *termstr;
726 struct winsize ws;
727 struct termios tio;
728 int ret;
729 int slave;
730
731 if (!ctx->interactive)
732 {
733 LOG_DEBUG ("Execing non interactively `%s'\n", ctx->args[0]);
734 pin = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_NO, 0, 0);
735 pout = GNUNET_DISK_pipe (GNUNET_NO, GNUNET_YES, 0, 0);
736 perr = GNUNET_DISK_pipe (GNUNET_NO, GNUNET_YES, 0, 0);
737 GNUNET_assert ((NULL != pin && (NULL != pout) && (NULL != perr)));
738 proc = GNUNET_OS_start_process_vap (GNUNET_NO,
739 GNUNET_OS_INHERIT_STD_NONE,
740 pin,
741 pout,
742 perr,
743 ctx->args[0],
744 ctx->args);
745 if (NULL == proc)
746 return GNUNET_SYSERR;
747 ctx->child_pid = GNUNET_OS_process_get_pid (proc);
748 GNUNET_OS_process_destroy (proc);
749 MSH_monitor_process_pid (ctx->child_pid, &proc_exit_cb, ctx);
750 ctx->fin = GNUNET_DISK_pipe_detach_end (pin, GNUNET_DISK_PIPE_END_WRITE);
751 ctx->fout = GNUNET_DISK_pipe_detach_end (pout, GNUNET_DISK_PIPE_END_READ);
752 ctx->ferr = GNUNET_DISK_pipe_detach_end (perr, GNUNET_DISK_PIPE_END_READ);
753 GNUNET_assert (((NULL != ctx->fin) && (NULL != ctx->fout) && (NULL != ctx->fout)));
754 GNUNET_assert (GNUNET_OK == GNUNET_DISK_pipe_close (pin));
755 GNUNET_assert (GNUNET_OK == GNUNET_DISK_pipe_close (pout));
756 GNUNET_assert (GNUNET_OK == GNUNET_DISK_pipe_close (perr));
757 ctx->fout_task =
758 GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
759 ctx->fout, &read_fout, ctx);
760 ctx->ferr_task =
761 GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
762 ctx->ferr, &read_ferr, ctx);
763 return GNUNET_OK;
764 }
765 LOG_DEBUG ("Execing interactively `%s'\n", ctx->args[0]);
766 if (NULL == (fnpty = ptsname (ctx->master)))
767 {
768 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "ptsname");
769 return GNUNET_SYSERR;
770 }
771 ret = fork ();
772 if (-1 == ret)
773 {
774 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "fork");
775 return GNUNET_SYSERR;
776 }
777 if (0 != ret)
778 {
779 int fd_in;
780 int fd_out;
781
782 LOG_DEBUG ("Forked child successfully\n");
783 ctx->child_pid = ret;
784 MSH_monitor_process_pid (ctx->child_pid, &proc_exit_cb, ctx);
785 /* forward streams to and from child */
786 fd_in = dup (ctx->master);
787 fd_out = dup (ctx->master);
788 /* We don't have to forward stderr here as that stream can also be read
789 from fd_out since it gets muxed at the pty */
790 //fd_err = dup (ctx->master);
791 GNUNET_break (0 == close (ctx->master));
792 if ( (-1 == fd_in) || (-1 == fd_out) )
793 {
794 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "dup");
795 GNUNET_assert (0 == kill (ret, SIGTERM));
796 return GNUNET_SYSERR;
797 }
798 ctx->fin = GNUNET_DISK_get_handle_from_int_fd (fd_in);
799 ctx->fout = GNUNET_DISK_get_handle_from_int_fd (fd_out);
800 ctx->fout_task =
801 GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, ctx->fout,
802 &read_fout, ctx);
803
804 return GNUNET_OK;
805 }
806 // GNUNET_log_setup ("mshd-server-child", NULL, NULL);
807 close (ctx->master);
808 LOG_DEBUG ("Opening slave PTY %s\n", fnpty);
809 slave = open (fnpty, O_RDWR);
810 if (-1 == slave)
811 {
812 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "open");
813 _exit (1);
814 }
815 if (-1 == tcgetattr (slave, &tio))
816 {
817 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "tcgetattr");
818 _exit (1);
819 }
820 termstr = NULL;
821 parse_term_mode (ctx->pty_mode, &tio, &ws, &termstr);
822 GNUNET_free (ctx->pty_mode);
823 ctx->pty_mode = NULL;
824 if (NULL != termstr)
825 {
826 GNUNET_break (0 == setenv ("TERM", termstr, 1));
827 GNUNET_free (termstr);
828 }
829 else
830 GNUNET_break (0 == setenv ("TERM", "MSH", 1));
831 if (-1 == tcsetattr (slave, TCSANOW, &tio))
832 {
833 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "tcsetattr");
834 //_exit (1); /* Ignore for now */
835 }
836 if (-1 == ioctl (slave, TIOCSWINSZ, &ws))
837 {
838 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "ioctl");
839 _exit (1);
840 }
841 if (-1 == setsid ())
842 {
843 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "setsid");
844 _exit (1);
845 }
846 close (0);
847 close (1);
848 close (2);
849 if ( (-1 == dup2 (slave, 0)) ||
850 (-1 == dup2 (slave, 1)) ||
851 (-1 == dup2 (slave, 2)) )
852 {
853 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "dup");
854 _exit (2);
855 }
856 close (slave);
857 GNUNET_break (0 == unsetenv ("LD_LIBRARY_PATH"));
858 GNUNET_break (0 == unsetenv ("LD_RUN_PATH"));
859 GNUNET_break (0 == unsetenv ("LD_LIBRARY_PATH_modshare"));
860 LOG_DEBUG ("Execing `%s'\n", ctx->args[0]);
861 if (-1 == execvp (ctx->args[0], ctx->args))
862 {
863 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "execvp");
864 _exit (1);
865 }
866 GNUNET_assert (0); /* This should never be reached */
867}
868
869
870/**
871 * Handle session open message and start challenge authentication.
872 *
873 * @param cls closure
874 * @param client identification of the client
875 * @param message the actual message
876 */
877static void
878handle_runcmd (void *cls,
879 struct GNUNET_SERVER_Client *client,
880 const struct GNUNET_MessageHeader* message)
881{
882 const struct MSH_MSG_RunCmd *msg;
883 struct ExecCtx *exec_ctx;
884 struct GNUNET_MessageHeader *reply;
885 uint16_t size;
886
887 LOG_DEBUG ("Received a RUN_CMD message\n");
888 exec_ctx = GNUNET_SERVER_client_get_user_context (client, struct ExecCtx);
889 GNUNET_assert (NULL != exec_ctx);
890 if (GNUNET_YES != exec_ctx->authenticated)
891 {
892 GNUNET_break_op (0);
893 goto close_conn;
894 }
895 if (exec_ctx->interactive && !exec_ctx->pty_opened)
896 {
897 GNUNET_break_op (0);
898 goto close_conn;
899 }
900 if (NULL != exec_ctx->args)
901 {
902 GNUNET_break (0);
903 goto close_conn;
904 }
905 size = ntohs (message->size);
906 if ( size <= sizeof (struct MSH_MSG_RunCmd))
907 {
908 GNUNET_break_op (0);
909 goto close_conn;
910 }
911 msg = (const struct MSH_MSG_RunCmd *) message;
912 if (0 == parse_strings (msg->cmd,
913 size - sizeof (struct MSH_MSG_RunCmd),
914 &exec_ctx->args))
915 {
916 GNUNET_break_op (0);
917 goto close_conn;
918 }
919 GNUNET_SCHEDULER_cancel (exec_ctx->timeout_task);
920 exec_ctx->timeout_task = GNUNET_SCHEDULER_NO_TASK;
921 if (GNUNET_OK != proc_exec (exec_ctx))
922 {
923 LOG (GNUNET_ERROR_TYPE_WARNING,
924 "Command `%s' not found or not executable\n", exec_ctx->args[0]);
925 goto close_conn;
926 }
927 reply = GNUNET_malloc (sizeof (struct GNUNET_MessageHeader));
928 reply->size = htons (sizeof (struct GNUNET_MessageHeader));
929 reply->type = htons (MSH_MTYPE_EXEC_BEGIN);
930 GNUNET_SERVER_notification_context_unicast (daemon_serv_nc, exec_ctx->client,
931 reply, GNUNET_NO);
932 GNUNET_SERVER_receive_done (client, GNUNET_OK);
933 return;
934
935 close_conn:
936 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
937}
938
939
940/**
941 * Functions with this signature are called whenever a message is
942 * received.
943 *
944 * @param cls NULL
945 * @param client identification of the client
946 * @param message the actual message
947 */
948static void
949handle_auth_challenge_response (void *cls,
950 struct GNUNET_SERVER_Client *client,
951 const struct GNUNET_MessageHeader* message)
952{
953 const struct MSH_MSG_ChallengeResponse *msg;
954 //struct GNUNET_MessageHeader *reply; FIXME
955 struct ExecCtx *exec_ctx;
956 struct GNUNET_HashCode cred;
957 struct GNUNET_CRYPTO_HashAsciiEncoded enc;
958
959 exec_ctx = GNUNET_SERVER_client_get_user_context (client, struct ExecCtx);
960 GNUNET_assert (NULL != exec_ctx);
961 auth_challenge_cred (&exec_ctx->salt, &cred);
962 GNUNET_CRYPTO_hash_to_enc (&cred, &enc);
963 msg = (const struct MSH_MSG_ChallengeResponse *) message;
964 if (0 != memcmp (&msg->auth, &enc,
965 sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)))
966 {
967 LOG_DEBUG ("Auth failed: \n"
968 " Required: %s\n"
969 " Given: %s\n", enc.encoding, msg->auth.encoding);
970 GNUNET_break (0);
971 goto err_ret;
972 }
973 exec_ctx->authenticated = GNUNET_YES;
974 GNUNET_SERVER_receive_done (client, GNUNET_OK);
975 return;
976
977 err_ret:
978 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
979}
980
981
982/**
983 * Task to write data from input buffer to proc's STDIN
984 *
985 * @param cls the client context
986 * @return tc scheduler task context
987 */
988static void
989write_fin (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
990{
991 struct ExecCtx *exec_ctx = cls;
992 ssize_t wrote;
993
994 exec_ctx->fin_task = GNUNET_SCHEDULER_NO_TASK;
995 if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_WRITE_READY))
996 {
997 GNUNET_free (exec_ctx->buf);
998 exec_ctx->buf = NULL;
999 exec_ctx->bufsize = 0;
1000 goto err_ret;
1001 }
1002 wrote = GNUNET_DISK_file_write (exec_ctx->fin,
1003 exec_ctx->buf, exec_ctx->bufsize);
1004 if (GNUNET_SYSERR == wrote)
1005 {
1006 LOG_ERROR ("Error writing to proc's STDIN\n");
1007 goto err_ret;
1008 }
1009 if (wrote == exec_ctx->bufsize)
1010 {
1011 GNUNET_free (exec_ctx->buf);
1012 exec_ctx->buf = NULL;
1013 exec_ctx->bufsize = 0;
1014 GNUNET_SERVER_receive_done (exec_ctx->client, GNUNET_OK);
1015 return;
1016 }
1017 GNUNET_assert (wrote < exec_ctx->bufsize);
1018 exec_ctx->bufsize -= wrote;
1019 exec_ctx->buf = memmove (exec_ctx->buf, exec_ctx->buf + wrote,
1020 exec_ctx->bufsize);
1021 exec_ctx->buf = GNUNET_realloc (exec_ctx->buf, exec_ctx->bufsize);
1022 exec_ctx->fin_task =
1023 GNUNET_SCHEDULER_add_write_file (GNUNET_TIME_UNIT_FOREVER_REL,
1024 exec_ctx->fin,
1025 &write_fin, exec_ctx);
1026 return;
1027
1028 err_ret:
1029 GNUNET_SERVER_receive_done (exec_ctx->client, GNUNET_SYSERR);
1030}
1031
1032
1033/**
1034 * Handler for messages with command's input stream data. The date will be
1035 * written to the command's standard input stream.
1036 *
1037 * @param cls NULL
1038 * @param client identification of the client
1039 * @param message the actual message
1040 */
1041static void
1042handle_command_input (void *cls,
1043 struct GNUNET_SERVER_Client *client,
1044 const struct GNUNET_MessageHeader* message)
1045{
1046 const struct MSH_MSG_CmdIO *msg;
1047 struct ExecCtx *exec_ctx;
1048 ssize_t wrote;
1049 uint16_t size;
1050
1051 LOG_DEBUG ("Received CMD_IO_STDIN message\n");
1052 size = ntohs (message->size);
1053 msg = (const struct MSH_MSG_CmdIO *) message;
1054 exec_ctx = GNUNET_SERVER_client_get_user_context (client, struct ExecCtx);
1055 GNUNET_assert (NULL != exec_ctx);
1056 size -= sizeof (struct MSH_MSG_CmdIO);
1057 wrote = GNUNET_DISK_file_write (exec_ctx->fin, msg->data, size);
1058 if (GNUNET_SYSERR == wrote)
1059 {
1060 LOG_ERROR ("Error writing to proc's STDIN\n");
1061 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1062 return;
1063 }
1064 LOG_DEBUG ("Wrote %zd to proc's STDIN\n", wrote);
1065 if (wrote == size)
1066 {
1067 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1068 return;
1069 }
1070 GNUNET_assert (wrote < size);
1071 GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == exec_ctx->fin_task);
1072 GNUNET_assert (NULL == exec_ctx->buf);
1073 GNUNET_assert (0 == exec_ctx->bufsize);
1074 exec_ctx->bufsize = size - wrote;
1075 exec_ctx->buf = GNUNET_malloc (exec_ctx->bufsize);
1076 (void) memcpy (exec_ctx->buf, msg->data + wrote, exec_ctx->bufsize);
1077 exec_ctx->fin_task =
1078 GNUNET_SCHEDULER_add_write_file (GNUNET_TIME_UNIT_FOREVER_REL,
1079 exec_ctx->fin,
1080 &write_fin, exec_ctx);
1081 GNUNET_SERVER_disable_receive_done_warning (client);
1082}
1083
1084
1085/**
1086 * Handler for messages containing the settings to be used while creating a
1087 * psuedo-tty. This message must only be received for interactive sessions
1088 * before #MSH_MSG_RunCmd message is received.
1089 *
1090 * @param cls NULL
1091 * @param client identification of the client
1092 * @param message the actual message
1093 */
1094static void
1095handle_pty_mode (void *cls,
1096 struct GNUNET_SERVER_Client *client,
1097 const struct GNUNET_MessageHeader* message)
1098{
1099 struct ExecCtx *exec_ctx;
1100 int master;
1101 uint16_t size;
1102
1103 size = ntohs (message->size);
1104 if (size <= sizeof (struct MSH_MSG_PtyMode))
1105 {
1106 GNUNET_break (0);
1107 goto close_conn;
1108 }
1109 exec_ctx = GNUNET_SERVER_client_get_user_context (client, struct ExecCtx);
1110 GNUNET_assert (NULL != exec_ctx);
1111 master = posix_openpt (O_RDWR);
1112 if (-1 == master)
1113 {
1114 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "posix_openpt");
1115 goto close_conn;
1116 }
1117 if (-1 == grantpt (master))
1118 {
1119 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "grantpt");
1120 goto close_conn;
1121 }
1122 if (-1 == unlockpt (master))
1123 {
1124 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "unlockpt");
1125 goto close_conn;
1126 }
1127 exec_ctx->master = master;
1128 exec_ctx->pty_opened = GNUNET_YES;
1129 exec_ctx->pty_mode = (struct MSH_MSG_PtyMode *) GNUNET_copy_message (message);
1130 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1131 return;
1132
1133 close_conn:
1134 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1135}
1136
1137
1138/**
1139 * Callback to be called when ever a client connects to the daemon server
1140 *
1141 * @param cls NULL
1142 * @param client the client handle
1143 */
1144static void
1145daemon_server_disconnect (void *cls, struct GNUNET_SERVER_Client *client)
1146{
1147 struct ExecCtx *exec_ctx;
1148
1149 if (NULL == client)
1150 return;
1151 LOG_DEBUG ("Remote client has disconnected\n");
1152 exec_ctx = GNUNET_SERVER_client_get_user_context (client, struct ExecCtx);
1153 GNUNET_assert (NULL != exec_ctx);
1154 destroy_exec_ctx (exec_ctx);
1155 GNUNET_SCHEDULER_shutdown ();
1156}
1157
1158
1159/**
1160 * Initialises the server which spawns processes and forwards it stdin and stdout
1161 *
1162 * @param h the network handle of the socket to listen for incoming connections
1163 */
1164int
1165init_daemon_server ()
1166{
1167 static const struct GNUNET_SERVER_MessageHandler handlers[] = {
1168 {&handle_session_open, NULL, MSH_MTYPE_SESSION_OPEN,
1169 sizeof (struct MSH_MSG_SessionOpen)},
1170 {&handle_runcmd, NULL, MSH_MTYPE_RUNCMD, 0},
1171 {&handle_auth_challenge_response, NULL, MSH_MTYPE_CHALLENGE_RESPONSE,
1172 sizeof (struct MSH_MSG_ChallengeResponse)},
1173 {&handle_command_input, NULL, MSH_MTYPE_CMD_STREAM_STDIN, 0},
1174 {&handle_pty_mode, NULL, MSH_MTYPE_PTY_MODE, 0},
1175 {NULL, NULL, 0, 0}
1176 };
1177
1178 daemon_serv = GNUNET_SERVER_create_with_sockets (NULL,
1179 NULL,
1180 NULL,
1181 GNUNET_TIME_UNIT_FOREVER_REL,
1182 GNUNET_YES);
1183 if (NULL == daemon_serv)
1184 return GNUNET_SYSERR;
1185 GNUNET_SERVER_add_handlers (daemon_serv, handlers);
1186 GNUNET_SERVER_disconnect_notify (daemon_serv, &daemon_server_disconnect, NULL);
1187 daemon_serv_nc = GNUNET_SERVER_notification_context_create (daemon_serv, 1);
1188 return GNUNET_OK;
1189}
1190
1191
1192/**
1193 * Timeout task for timing out connections until they authenticate. Once
1194 * authenticated the connection will not be timed out.
1195 *
1196 * @param cls the client context
1197 * @param tc scheduler task context
1198 */
1199static void
1200timeout_cb (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1201{
1202 struct ExecCtx *exec_ctx = cls;
1203
1204 exec_ctx->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1205 GNUNET_SERVER_client_disconnect (exec_ctx->client);
1206}
1207
1208
1209/**
1210 * Create a client for the daemon server from a new client connection
1211 *
1212 * @param conn the connection to derive the client from
1213 */
1214void
1215daemon_server_add_connection (struct GNUNET_CONNECTION_Handle *conn)
1216{
1217 struct ExecCtx *exec_ctx;
1218 struct GNUNET_SERVER_Client *client;
1219
1220 exec_ctx = GNUNET_malloc (sizeof (struct ExecCtx));
1221 client = GNUNET_SERVER_connect_socket (daemon_serv, conn);
1222 exec_ctx->client = client;
1223 GNUNET_SERVER_client_set_user_context (client, exec_ctx);
1224 GNUNET_SERVER_notification_context_add (daemon_serv_nc, client);
1225 exec_ctx->timeout_task =
1226 GNUNET_SCHEDULER_add_delayed (TIMEOUT_SECS (30), &timeout_cb, exec_ctx);
1227}
1228
1229
1230/**
1231 * Shutdown the daemon server
1232 */
1233void
1234shutdown_daemon_server ()
1235{
1236 if (NULL != daemon_serv)
1237 {
1238 GNUNET_SERVER_destroy (daemon_serv);
1239 daemon_serv = NULL;
1240 }
1241 if (NULL != daemon_serv_nc)
1242 {
1243 GNUNET_SERVER_notification_context_destroy (daemon_serv_nc);
1244 daemon_serv_nc = NULL;
1245 }
1246}
1247
1248/* End of server.c */
diff --git a/src/server.h b/src/server.h
new file mode 100644
index 0000000..ca44c86
--- /dev/null
+++ b/src/server.h
@@ -0,0 +1,56 @@
1/**
2 * @file server.c
3 * @brief functions implementing server functionalities of MSH daemon. We
4 * listen for commands from locally started MSH instances and also for
5 * executing commands given by remote MSH daemons.
6 * @author Sree Harsha Totakura <sreeharsha@totakura.in>
7 */
8
9#ifndef MSHD_SERVER_H_
10#define MSHD_SERVER_H_
11
12
13/**
14 * Shutdown the local server
15 */
16void
17shutdown_local_server ();
18
19
20/**
21 * Shutdown the daemon server
22 */
23void
24shutdown_daemon_server ();
25
26
27/**
28 * Create a client for the daemon server from a new client connection
29 *
30 * @param conn the connection to derive the client from
31 */
32void
33daemon_server_add_connection (struct GNUNET_CONNECTION_Handle *conn);
34
35
36/**
37 * Initialises the server which spawns processes and forwards it stdin and stdout
38 *
39 * @param h the network handle of the socket to listen for incoming connections
40 */
41int
42init_daemon_server ();
43
44
45/**
46 * Initialise the local server
47 *
48 * @param unixpath the name to use while opening the abstract UNIX domain socket
49 * for listening
50 * @return GNUNET_OK upon success; GNUNET_SYSERR upon failure
51 */
52int
53init_local_server (const char *unixpath);
54
55
56#endif /* MSHD_SERVER_H_ */
diff --git a/src/test_addressmap.c b/src/test_addressmap.c
new file mode 100644
index 0000000..877cb07
--- /dev/null
+++ b/src/test_addressmap.c
@@ -0,0 +1,164 @@
1/**
2 * @file test_addressmap.c
3 * @brief test case for address map implementation
4 * @author Sree Harsha Totakura <sreeharsha@totakura.in>
5 */
6
7#include "common.h"
8#include <gnunet/gnunet_util_lib.h>
9#include "util.h"
10#include "addressmap.h"
11#include "mtypes.h"
12
13#define LOG(kind,...) \
14 GNUNET_log_from (kind, "mshd-addressmap", __VA_ARGS__)
15
16#define LOG_DEBUG(...) LOG(GNUNET_ERROR_TYPE_DEBUG, __VA_ARGS__)
17
18#define LOG_ERROR(...) LOG(GNUNET_ERROR_TYPE_ERROR, __VA_ARGS__)
19
20#define LOG_STRERROR(cmd) \
21 GNUNET_log_from_strerror (GNUNET_ERROR_TYPE_WARNING, "test-addressmap", cmd)
22
23
24static unsigned int cnt;
25
26
27/**
28 * Callback for iterating all the instance addresses present in an instance
29 * address info object
30 *
31 * @param cls the closure passed to instance_address_info_iterate_addresses()
32 * @param port the port where the instance is listening
33 * @param ip the ip of the instance
34 * @return GNUNET_OK to continue iteration; GNUNET_SYSERR to terminate
35 */
36static int
37iterator_cb (void *cls, uint16_t port, in_addr_t ip)
38{
39 cnt++;
40 return GNUNET_OK;
41}
42
43
44static void
45test_serialization (AddressMap *m)
46{
47 struct MSH_MSG_InstanceAdresses **iaddr_msgs;
48 int n;
49 unsigned int cnt;
50
51 GNUNET_assert (0 < (n = addressmap_pack (m, &iaddr_msgs)));
52 for (cnt = 0; cnt < n; cnt++)
53 {
54 free (iaddr_msgs[cnt]);
55 }
56 free (iaddr_msgs);
57}
58
59
60static int
61instance_address_info_free_iterator (void *cls, struct InstanceAddrInfo *iainfo)
62{
63 instance_address_info_destroy (iainfo);
64 return GNUNET_OK;
65}
66
67
68static void
69test_deserialization ()
70{
71 AddressMap *m;
72 struct MSH_MSG_InstanceAdresses **iaddr_msgs;
73
74 m = addressmap_create (2);
75 GNUNET_assert (GNUNET_OK == addressmap_add (m, 1, 0, 12));
76 GNUNET_assert (GNUNET_OK == addressmap_add (m, 1, 0, 2));
77 GNUNET_assert (GNUNET_OK == addressmap_add (m, 1, 0, 7));
78 GNUNET_assert (GNUNET_OK == addressmap_add (m, 1, 0, 14));
79 cnt = 0;
80 GNUNET_assert (GNUNET_OK ==
81 addressmap_iterate_instance_addresses (m, 1, &iterator_cb, NULL));
82 GNUNET_assert (4 == cnt);
83
84 /* prepare a second addressmap */
85 {
86 AddressMap *m2;
87 struct MSH_MSG_AddressMap *map_msg;
88
89 m2 = addressmap_create (2);
90 GNUNET_assert (GNUNET_OK == addressmap_add (m2, 1, 0, 2));
91 GNUNET_assert (GNUNET_OK == addressmap_add (m2, 1, 0, 7));
92 GNUNET_assert (GNUNET_OK == addressmap_add (m2, 1, 0, 14));
93 GNUNET_assert (GNUNET_OK == addressmap_add (m2, 0, 0, 3));
94 cnt = 0;
95 GNUNET_assert (GNUNET_OK ==
96 addressmap_iterate_instance_addresses (m2, 1, &iterator_cb, NULL));
97 GNUNET_assert (3 == cnt);
98 cnt = 0;
99 GNUNET_assert (GNUNET_OK ==
100 addressmap_iterate_instance_addresses (m2, 0, &iterator_cb, NULL));
101 GNUNET_assert (1 == cnt);
102 GNUNET_assert (0 < addressmap_pack (m2, &iaddr_msgs));
103 addressmap_destroy (m2);
104 }
105 /* check intersection of the message with the first addressmap */
106 GNUNET_assert (3 == addressmap_intersect_msg (m, iaddr_msgs[1]));
107 cnt = 0;
108 GNUNET_assert (GNUNET_OK ==
109 addressmap_iterate_instance_addresses (m, 1, &iterator_cb, NULL));
110 GNUNET_assert (3 == cnt);
111 addressmap_destroy (m);
112 free (iaddr_msgs[1]);
113 free (iaddr_msgs[0]);
114 free (iaddr_msgs);
115}
116
117
118int
119main ()
120{
121 AddressMap *m;
122 struct InstanceAddr *addr1, *addr2, *addr3;
123 struct InstanceAddrInfo *iainfo;
124
125 m = addressmap_create (2);
126 GNUNET_assert (GNUNET_OK == addressmap_add (m, 0, 0, 12));
127 GNUNET_assert (GNUNET_OK == addressmap_add (m, 0, 0, 9));
128 GNUNET_assert (GNUNET_OK == addressmap_add (m, 0, 0, 13));
129 cnt = 0;
130 GNUNET_assert (GNUNET_OK ==
131 addressmap_iterate_instance_addresses (m, 0, &iterator_cb, NULL));
132 GNUNET_assert (3 == cnt);
133
134 GNUNET_assert (GNUNET_OK != addressmap_add (m, 0, 0, 12)); /* 12 was added before */
135 GNUNET_assert (GNUNET_OK == addressmap_add (m, 0, 0, 19));
136 cnt = 0;
137 GNUNET_assert (GNUNET_OK ==
138 addressmap_iterate_instance_addresses (m, 0, &iterator_cb, NULL));
139 GNUNET_assert (4 == cnt);
140
141 /* test address map intersections */
142 iainfo = instance_address_info_create (0);
143 addr1 = instance_address_create_sockaddr_in (0, 12);
144 instance_address_info_add_address (iainfo, addr1);
145 addr2 = instance_address_create_sockaddr_in (0, 19);
146 instance_address_info_add_address (iainfo, addr2);
147 addr3 = instance_address_create_sockaddr_in (0, 3);
148 instance_address_info_add_address (iainfo, addr3);
149 addressmap_intersect (m, iainfo);
150 cnt = 0;
151 GNUNET_assert (GNUNET_OK ==
152 addressmap_iterate_instance_addresses (m, 0, &iterator_cb, NULL));
153 GNUNET_assert (2 == cnt);
154 instance_address_info_destroy (iainfo);
155
156 /* test message serialization of the addressmap */
157 GNUNET_assert (GNUNET_OK == addressmap_add (m, 1, 0, 99));
158 test_serialization (m);
159 addressmap_destroy (m);
160
161 /* test message deserialization of the addressmap */
162 test_deserialization ();
163 return 0;
164}
diff --git a/src/test_bitmap.c b/src/test_bitmap.c
new file mode 100644
index 0000000..1dc3f8f
--- /dev/null
+++ b/src/test_bitmap.c
@@ -0,0 +1,54 @@
1/**
2 * @file test_bitmap.c
3 * @brief testcase for bitmap
4 * @author Sree Harsha Totakura <sreeharsha@totakura.in>
5 */
6
7#include "common.h"
8#include <gnunet/gnunet_util_lib.h>
9#include "bitmap.h"
10
11#define LOG(kind,...) \
12 GNUNET_log_from (kind, "mshd-addressmap", __VA_ARGS__)
13
14#define LOG_DEBUG(...) LOG(GNUNET_ERROR_TYPE_DEBUG, __VA_ARGS__)
15
16#define LOG_ERROR(...) LOG(GNUNET_ERROR_TYPE_ERROR, __VA_ARGS__)
17
18#define LOG_STRERROR(cmd) \
19 GNUNET_log_from_strerror (GNUNET_ERROR_TYPE_WARNING, "test-bitmap", cmd)
20
21#define FAIL_TEST(cond,ret) \
22do { if (!cond){fprintf (stderr, "Assertion failed at %s:%d\n", __FILE__, __LINE__); ret;} }while(0)
23
24int main ()
25{
26 struct BitMap *bm;
27 unsigned int len = 80;
28 unsigned int cnt;
29
30 bm = bitmap_create (len);
31 bitmap_set (bm, 13, 1);
32 GNUNET_assert (1 == bitmap_isbitset (bm, 13));
33 for (cnt = 0; cnt < len; cnt++)
34 {
35 if (cnt == 13)
36 continue;
37 FAIL_TEST (0 == bitmap_isbitset (bm, cnt), return 1);
38 }
39 bitmap_clear (bm);
40 for (cnt = 0; cnt < len; cnt++)
41 {
42 FAIL_TEST (0 == bitmap_isbitset (bm, cnt), return 1);
43 }
44 bitmap_destroy (bm);
45 len = 9;
46 bm = bitmap_create (len);
47 for (cnt = 0; cnt < len; cnt++)
48 {
49 bitmap_set (bm, cnt, 1);
50 }
51 FAIL_TEST (1 == bitmap_allset (bm), return 1);
52 bitmap_destroy (bm);
53 return 0;
54}
diff --git a/src/test_mping.sh b/src/test_mping.sh
new file mode 100755
index 0000000..94126f0
--- /dev/null
+++ b/src/test_mping.sh
@@ -0,0 +1,12 @@
1#!/bin/sh
2#SBATCH -o /home/hpc/pr86mo/di72zus/test/myjob.%j.%N.out
3#SBATCH -D /home/hpc/pr86mo/di72zus/test
4#SBATCH -J testjob
5#SBATCH --clusters=serial
6#SBATCH --partition=serial_std
7#SBATCH --mail-type=end
8#SBATCH --mail-user=totakura@in.tum.de
9#SBATCH --time=00:01:00
10
11hostname
12uptime
diff --git a/src/test_pty.c b/src/test_pty.c
new file mode 100644
index 0000000..b1efae1
--- /dev/null
+++ b/src/test_pty.c
@@ -0,0 +1,666 @@
1#include "common.h"
2#include <gnunet/gnunet_util_lib.h>
3#include <termios.h>
4#include "mtypes.h"
5
6/****************************************************************************/
7/* Implemented after http://rachid.koucha.free.fr/tech_corner/pty_pdip.html */
8/****************************************************************************/
9
10#define LOG(kind,...) \
11 GNUNET_log (kind, __VA_ARGS__)
12
13#define LOG_DEBUG(...) LOG(GNUNET_ERROR_TYPE_DEBUG, __VA_ARGS__)
14
15#define LOG_ERROR(...) LOG(GNUNET_ERROR_TYPE_ERROR, __VA_ARGS__)
16
17#define TIMEOUT(secs) \
18 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, secs)
19
20#define DEFAULT_TIMEOUT TIMEOUT(30)
21
22#define BUF_SIZE 512
23
24/**
25 * handler for SIGCHLD.l Register it just before forking
26 */
27static struct GNUNET_SIGNAL_Context *shc_chld;
28
29/**
30 * Task to kill the child
31 */
32static GNUNET_SCHEDULER_TaskIdentifier child_death_task;
33
34/**
35 * Task to read output from child
36 */
37static GNUNET_SCHEDULER_TaskIdentifier read_child_task;
38
39/**
40 * Pipe used to communicate shutdown via signal.
41 */
42static struct GNUNET_DISK_PipeHandle *sigpipe;
43
44static struct GNUNET_DISK_FileHandle *chld_io;
45
46static struct GNUNET_CONNECTION_Handle *conn;
47
48static struct GNUNET_CONNECTION_TransmitHandle *tx;
49
50static char **chld_argv;
51
52static char *cp;
53static struct termios tio;
54static struct winsize ws;
55
56static int in_receive;
57
58static char buf[BUF_SIZE];
59static size_t buf_off;
60
61/**
62 * The process id of the child
63 */
64static pid_t child_pid;
65
66/**
67 * Function to copy NULL terminated list of arguments
68 *
69 * @param argv the NULL terminated list of arguments. Cannot be NULL.
70 * @return the copied NULL terminated arguments
71 */
72static char **
73copy_argv (char *const *argv)
74{
75 char **argv_dup;
76 unsigned int argp;
77
78 GNUNET_assert (NULL != argv);
79 for (argp = 0; NULL != argv[argp]; argp++) ;
80 argv_dup = GNUNET_malloc (sizeof (char *) * (argp + 1));
81 for (argp = 0; NULL != argv[argp]; argp++)
82 argv_dup[argp] = strdup (argv[argp]);
83 return argv_dup;
84}
85
86
87/**
88 * Frees the given NULL terminated arguments
89 *
90 * @param argv the NULL terminated list of arguments
91 */
92static void
93free_argv (char **argv)
94{
95 unsigned int argp;
96
97 for (argp = 0; NULL != argv[argp]; argp++)
98 GNUNET_free (argv[argp]);
99 GNUNET_free (argv);
100}
101
102
103/**
104 * shutdown task
105 */
106static void
107do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
108{
109 if (NULL != chld_argv)
110 {
111 free_argv (chld_argv);
112 chld_argv = NULL;
113 }
114 if (NULL != conn)
115 {
116 if (in_receive)
117 GNUNET_CONNECTION_receive_cancel (conn);
118 if (NULL != tx)
119 GNUNET_CONNECTION_notify_transmit_ready_cancel (tx);
120 GNUNET_CONNECTION_destroy (conn);
121 conn = NULL;
122 }
123 if (0 != child_pid)
124 {
125 GNUNET_break (0 == kill (child_pid, SIGTERM));
126 LOG_DEBUG ("Child still running. Delaying shutdown\n");
127 (void) GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
128 &do_shutdown, NULL);
129 return;
130 }
131 if (GNUNET_SCHEDULER_NO_TASK != child_death_task)
132 {
133 GNUNET_SCHEDULER_cancel (child_death_task);
134 child_death_task = GNUNET_SCHEDULER_NO_TASK;
135 }
136 if (NULL != chld_io)
137 GNUNET_DISK_file_close (chld_io);
138}
139
140
141/**
142 * Read the child processes output and send it to over network connection to waiter
143 */
144static void
145read_child (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
146
147
148/**
149 * Function called to notify a client about the connection
150 * begin ready to queue more data. "buf" will be
151 * NULL and "size" zero if the connection was closed for
152 * writing in the meantime.
153 *
154 * @param cls closure
155 * @param size number of bytes available in buf
156 * @param netbuf where the callee should write the message
157 * @return number of bytes written to buf
158 */
159static size_t
160do_tx (void *cls, size_t size, void *netbuf)
161{
162 tx = NULL;
163 if ((NULL == buf) || (0 == size))
164 {
165 LOG_ERROR ("Failure in connectivity\n");
166 GNUNET_SCHEDULER_shutdown ();
167 return 0;
168 }
169 GNUNET_assert (buf_off <= size);
170 (void) memcpy (netbuf, buf, buf_off);
171 size = buf_off;
172 buf_off = 0;
173 if (GNUNET_SCHEDULER_NO_TASK == read_child_task)
174 read_child_task =
175 GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, chld_io,
176 &read_child, NULL);
177 return size;
178}
179
180
181/**
182 * Read the child processes output and send it to over network connection to waiter
183 */
184static void
185read_child (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
186{
187 ssize_t rsize;
188
189 read_child_task = GNUNET_SCHEDULER_NO_TASK;
190 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
191 return;
192 if (BUF_SIZE == buf_off)
193 {
194 GNUNET_assert (NULL != tx);
195 return;
196 }
197 rsize = GNUNET_DISK_file_read (chld_io, buf + buf_off, BUF_SIZE - buf_off);
198 if (rsize <= 0)
199 {
200 LOG_DEBUG ("Child stdout closed\n");
201 return;
202 }
203 buf_off += rsize;
204 if (NULL != tx)
205 GNUNET_CONNECTION_notify_transmit_ready_cancel (tx);
206 tx = GNUNET_CONNECTION_notify_transmit_ready (conn, buf_off, DEFAULT_TIMEOUT,
207 &do_tx, NULL);
208 if (BUF_SIZE == buf_off)
209 return;
210 read_child_task =
211 GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, chld_io,
212 &read_child, NULL);
213}
214
215
216/**
217 * Task triggered whenever we receive a SIGCHLD (child
218 * process died).
219 *
220 * @param cls closure, NULL if we need to self-restart
221 * @param tc context
222 */
223static void
224child_died (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
225{
226 const struct GNUNET_DISK_FileHandle *pr;
227 char c[16];
228
229 pr = GNUNET_DISK_pipe_handle (sigpipe, GNUNET_DISK_PIPE_END_READ);
230 child_death_task = GNUNET_SCHEDULER_NO_TASK;
231 if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_READ_READY))
232 {
233 child_death_task =
234 GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
235 pr, &child_died, NULL);
236 return;
237 }
238 /* consume the signal */
239 GNUNET_break (0 < GNUNET_DISK_file_read (pr, &c, sizeof (c)));
240 LOG_DEBUG ("Child died\n");
241 child_pid = 0;
242 GNUNET_SCHEDULER_shutdown ();
243 /* FIXME: read any of the left over output from child? */
244}
245
246
247/**
248 * Signal handler called for SIGCHLD.
249 */
250static void
251sighandler_child_death ()
252{
253 static char c;
254 int old_errno = errno; /* back-up errno */
255
256 GNUNET_break (1 ==
257 GNUNET_DISK_file_write (GNUNET_DISK_pipe_handle
258 (sigpipe, GNUNET_DISK_PIPE_END_WRITE),
259 &c, sizeof (c)));
260 errno = old_errno; /* restore errno */
261}
262
263
264/**
265 * Configure the terminal for the child
266 */
267static int
268parse_term_mode (const struct MSH_MSG_PtyMode *msg)
269{
270 uint16_t *params;
271 unsigned int cnt;
272 unsigned int ns;
273 uint16_t msize;
274 size_t expected;
275 speed_t ospeed;
276 speed_t ispeed;
277
278 msize = ntohs (msg->header.size);
279 ns = ntohs (msg->nsettings);
280 expected = (sizeof (struct MSH_MSG_PtyMode) + (sizeof (uint16_t) * ns * 2));
281 if (msize < expected)
282 {
283 GNUNET_break (0);
284 return GNUNET_SYSERR;
285 }
286#define PARSE_WIN_SIZE(field) \
287 ws.field = ntohs (msg->field);
288 PARSE_WIN_SIZE (ws_row);
289 PARSE_WIN_SIZE (ws_col);
290 PARSE_WIN_SIZE (ws_xpixel);
291 PARSE_WIN_SIZE (ws_ypixel);
292#undef PARSE_WIN_SIZE
293 ospeed = baud_to_speed (ntohl (msg->ospeed));
294 ispeed = baud_to_speed (ntohl (msg->ispeed));
295 if (0 != cfsetospeed (&tio, ospeed))
296 {
297 GNUNET_break (0);
298 return GNUNET_SYSERR;
299 }
300 if (0 != cfsetispeed (&tio, ispeed))
301 {
302 GNUNET_break (0);
303 return GNUNET_SYSERR;
304 }
305 params = (uint16_t *) &msg[1];
306 for (cnt = 0; cnt < ns; cnt++)
307 {
308 switch (ntohs (params[2 * cnt]))
309 {
310#define TTYCHAR(NAME,OP) \
311 case OP: \
312 tio.c_cc[NAME] = ntohs (params[(2 * cnt)+1]); \
313 break;
314#define TTYMODE(NAME, FIELD, OP) \
315 case OP: \
316 if (1 == ntohs (params[(2 * cnt)+1])) \
317 tio.FIELD |= NAME; \
318 break;
319#include "ttymodes.h"
320#undef TTYCHAR
321#undef TTYMODE
322
323 default:
324 GNUNET_assert (0);
325 }
326 }
327 if (0 == (msize - expected))
328 return GNUNET_OK;
329 cp = ((void *) msg) + expected;
330 if ('\0' != cp[(msize - expected) - 1])
331 {
332 GNUNET_break (0);
333 cp = NULL;
334 return GNUNET_OK;
335 }
336 cp = GNUNET_strdup (cp);
337 return GNUNET_OK;
338}
339
340
341/**
342 * Create pty, fork, setup the tty modes and exec the given binary
343 */
344static int
345spawn_child (const struct MSH_MSG_PtyMode *msg)
346{
347 const char *fn;
348 int master;
349 int ret;
350
351 LOG_DEBUG ("Creating PTY\n");
352 master = posix_openpt (O_RDWR);
353 if (-1 == master)
354 {
355 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "posix_openpt");
356 goto err_ret;
357 }
358 if (-1 == grantpt (master))
359 {
360 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "grantpt");
361 goto err_ret;
362 }
363 if (-1 == unlockpt (master))
364 {
365 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "unlockpt");
366 goto err_ret;
367 }
368 if (NULL == (fn = ptsname (master)))
369 {
370 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "ptsname");
371 goto err_ret;
372 }
373 shc_chld =
374 GNUNET_SIGNAL_handler_install (GNUNET_SIGCHLD, &sighandler_child_death);
375 ret = fork();
376 if (-1 == ret)
377 {
378 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "fork");
379 goto err_ret;
380 }
381 if (0 != ret)
382 {
383 LOG_DEBUG ("Forked child successfully\n");
384 child_pid = ret;
385 chld_io = GNUNET_DISK_get_handle_from_int_fd (master);
386 read_child_task =
387 GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, chld_io,
388 &read_child, NULL);
389 return GNUNET_OK;
390 }
391 /* child process */
392 {
393 int slave;
394
395 close (master);
396 LOG_DEBUG ("Opening slave PTY %s\n", fn);
397 slave = open (fn, O_RDWR);
398 if (-1 == slave)
399 {
400 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "open");
401 _exit (1);
402 }
403 if (-1 == tcgetattr (slave, &tio))
404 {
405 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "tcsetattr");
406 _exit (1);
407 }
408 parse_term_mode (msg);
409 if (-1 == tcsetattr (slave, TCSANOW, &tio))
410 {
411 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "tcsetattr");
412 //_exit (1); /* Ignore for now */
413 }
414 if (-1 == ioctl (slave, TIOCSWINSZ, &ws))
415 {
416 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "ioctl");
417 _exit (1);
418 }
419 if (-1 == setsid ())
420 {
421 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "setsid");
422 _exit (1);
423 }
424 close (0);
425 close (1);
426 close (2);
427 if ( (-1 == dup2 (slave, 0)) ||
428 (-1 == dup2 (slave, 1)) ||
429 (-1 == dup2 (slave, 2)) )
430 {
431 //GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "dup"); //we won't get it
432 //at this point
433 _exit (2);
434 }
435 close (slave);
436 LOG_DEBUG ("Execing %s\n", chld_argv[0]);
437 if (-1 == execvp (chld_argv[0], chld_argv))
438 {
439 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "execvp");
440 _exit (1);
441 }
442 }
443
444 err_ret:
445 GNUNET_SCHEDULER_shutdown ();
446 return GNUNET_SYSERR;
447}
448
449
450/**
451 * Callback function for data received from the network. Note that
452 * both "available" and "err" would be 0 if the read simply timed out.
453 *
454 * @param cls closure
455 * @param buf pointer to received data
456 * @param available number of bytes availabe in "buf",
457 * possibly 0 (on errors)
458 * @param addr address of the sender
459 * @param addrlen size of addr
460 * @param errCode value of errno (on errors receiving)
461 */
462static void
463net_receive (void *cls, const void *buf, size_t available,
464 const struct sockaddr * addr, socklen_t addrlen, int errCode)
465{
466 static enum {
467 STATE_HEADER = 0,
468 STATE_MSG,
469 STATE_FORWARD
470 } state;
471 static size_t rb;
472 struct GNUNET_TIME_Relative timeout;
473 static struct MSH_MSG_PtyMode *msg;
474 size_t rsize;
475
476 in_receive = 0;
477 if (0 == available)
478 {
479 GNUNET_SCHEDULER_shutdown ();
480 return;
481 }
482 switch (state)
483 {
484 case STATE_HEADER:
485 {
486 static struct GNUNET_MessageHeader hdr;
487 uint16_t msize;
488
489 GNUNET_assert (available <= sizeof (hdr));
490 memcpy (((void *) &hdr) + rb, buf, available);
491 rb += available;
492 timeout = DEFAULT_TIMEOUT;
493 rsize = sizeof (hdr) - rb;
494 if (0 != rsize)
495 goto read_again;
496 if (MSH_MTYPE_PTY_MODE != ntohs (hdr.type))
497 {
498 GNUNET_break_op (0);
499 GNUNET_SCHEDULER_shutdown ();
500 return;
501 }
502 msize = ntohs (hdr.size);
503 msg = GNUNET_malloc (msize);
504 memcpy (msg, &hdr, sizeof (hdr));
505 rsize = msize - sizeof (hdr);
506 state = STATE_MSG;
507 goto read_again;
508 }
509 case STATE_MSG:
510 {
511 uint16_t msize;
512
513 msize = ntohs (msg->header.size);
514 GNUNET_assert (available <= (msize - rb));
515 memcpy (((void *) msg) + rb, buf, available);
516 rb += available;
517 timeout = DEFAULT_TIMEOUT;
518 rsize = msize - rb;
519 if (0 != rsize)
520 goto read_again;
521 spawn_child (msg);
522 GNUNET_free (msg);
523 msg = NULL;
524 state = STATE_FORWARD;
525 }
526 break;
527 case STATE_FORWARD:
528 /* receive from net and write to child pty */
529 {
530 size_t wb;
531 ssize_t ret;
532
533 wb = 0;
534 do {
535 ret = GNUNET_DISK_file_write (chld_io, buf + wb, available - wb);
536 if (GNUNET_SYSERR == ret)
537 {
538 GNUNET_break (0);
539 GNUNET_SCHEDULER_shutdown ();
540 return;
541 }
542 wb += ret;
543 } while (wb < available);
544 }
545 break;
546 }
547 rsize = BUF_SIZE;
548 timeout = GNUNET_TIME_UNIT_FOREVER_REL;
549
550 read_again:
551 GNUNET_CONNECTION_receive (conn, rsize, timeout, &net_receive, NULL);
552 in_receive = 1;
553}
554
555
556/**
557 * Main function that will be run by the scheduler.
558 *
559 * @param cls closure
560 * @param args remaining command-line arguments
561 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
562 * @param c configuration
563 */
564static void
565run (void *cls,
566 char *const *args,
567 const char *cfgfile,
568 const struct GNUNET_CONFIGURATION_Handle *c)
569{
570 unsigned int argc;
571 const char *hostname;
572 const char *portstr;
573 struct sockaddr *addr;
574 struct addrinfo *res;
575 struct addrinfo hints;
576 int af_family;
577 socklen_t addrlen;
578 int ret;
579
580 argc = 0;
581 hostname = args[argc++];
582 if (NULL == hostname)
583 {
584 GNUNET_break (0);
585 return;
586 }
587 portstr = args[argc++];
588 if (NULL == portstr)
589 {
590 GNUNET_break (0);
591 return;
592 }
593 if (NULL == args[argc])
594 {
595 GNUNET_break (0);
596 return;
597 }
598 (void) memset (&hints, 0, sizeof (hints));
599 hints.ai_flags = AI_NUMERICSERV;
600 hints.ai_family = AF_INET;
601 hints.ai_socktype = SOCK_STREAM;
602 ret = getaddrinfo (hostname, portstr, &hints, &res);
603 if (0 != ret)
604 {
605 LOG_ERROR ("getaddrinfo() failed: %s\n", gai_strerror (ret));
606 return;
607 }
608 if (NULL == res)
609 {
610 GNUNET_break (0);
611 return;
612 }
613 addrlen = res->ai_addrlen;
614 addr = GNUNET_malloc (addrlen);
615 memcpy (addr, res->ai_addr, addrlen);
616 af_family = res->ai_family;
617 freeaddrinfo (res);
618 conn = GNUNET_CONNECTION_create_from_sockaddr (af_family, addr, addrlen);
619 GNUNET_free (addr);
620 if (NULL == conn)
621 {
622 GNUNET_break (0);
623 return;
624 }
625 GNUNET_CONNECTION_receive (conn, sizeof (struct GNUNET_MessageHeader),
626 DEFAULT_TIMEOUT, &net_receive, NULL);
627 in_receive = 1;
628 child_death_task =
629 GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
630 GNUNET_DISK_pipe_handle (sigpipe,
631 GNUNET_DISK_PIPE_END_READ),
632 &child_died, NULL);
633 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
634 &do_shutdown, NULL);
635 chld_argv = copy_argv (&args[argc]);
636 return;
637}
638
639
640int main(int argc, char *const argv[])
641{
642 static const struct GNUNET_GETOPT_CommandLineOption options[] = {
643 GNUNET_GETOPT_OPTION_END
644 };
645 int ret;
646
647 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
648 return 2;
649 if (NULL == (sigpipe = GNUNET_DISK_pipe (GNUNET_NO, GNUNET_NO,
650 GNUNET_NO, GNUNET_NO)))
651 {
652 GNUNET_break (0);
653 return 1;
654 }
655 ret =
656 GNUNET_PROGRAM_run (argc, argv, "test-pty",
657 gettext_noop
658 ("msh-waiter test program"),
659 options, &run, NULL);
660 if (NULL != shc_chld)
661 GNUNET_SIGNAL_handler_uninstall (shc_chld);
662 GNUNET_DISK_pipe_close (sigpipe);
663 GNUNET_free ((void *) argv);
664 LOG_DEBUG ("Exiting\n");
665 return ret;
666}
diff --git a/src/ttymodes.c b/src/ttymodes.c
new file mode 100644
index 0000000..eac35b8
--- /dev/null
+++ b/src/ttymodes.c
@@ -0,0 +1,484 @@
1/* $OpenBSD: ttymodes.c,v 1.29 2008/11/02 00:16:16 stevesk Exp $ */
2/*
3 * Author: Tatu Ylonen <ylo@cs.hut.fi>
4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
5 * All rights reserved
6 *
7 * As far as I am concerned, the code I have written for this software
8 * can be used freely for any purpose. Any derived versions of this
9 * software must be clearly marked as such, and if the derived work is
10 * incompatible with the protocol description in the RFC file, it must be
11 * called by a name other than "ssh" or "Secure Shell".
12 */
13
14/*
15 * SSH2 tty modes support by Kevin Steves.
16 * Copyright (c) 2001 Kevin Steves. All rights reserved.
17 *
18 * Redistribution and use in source and binary forms, with or without
19 * modification, are permitted provided that the following conditions
20 * are met:
21 * 1. Redistributions of source code must retain the above copyright
22 * notice, this list of conditions and the following disclaimer.
23 * 2. Redistributions in binary form must reproduce the above copyright
24 * notice, this list of conditions and the following disclaimer in the
25 * documentation and/or other materials provided with the distribution.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
28 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
29 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
30 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
31 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
32 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
33 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
34 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
35 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
36 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 */
38
39/*
40 * Encoding and decoding of terminal modes in a portable way.
41 * Much of the format is defined in ttymodes.h; it is included multiple times
42 * into this file with the appropriate macro definitions to generate the
43 * suitable code.
44 */
45
46#include "common.h"
47
48#include <termios.h>
49
50#define TTY_OP_END 0
51
52/*
53 * uint32 (u_int) follows speed in SSH1 and SSH2
54 */
55#define TTY_OP_ISPEED_PROTO1 192
56#define TTY_OP_OSPEED_PROTO1 193
57#define TTY_OP_ISPEED_PROTO2 128
58#define TTY_OP_OSPEED_PROTO2 129
59
60/*
61 * Converts POSIX speed_t to a baud rate. The values of the
62 * constants for speed_t are not themselves portable.
63 */
64int
65speed_to_baud(speed_t speed)
66{
67 switch (speed) {
68 case B0:
69 return 0;
70 case B50:
71 return 50;
72 case B75:
73 return 75;
74 case B110:
75 return 110;
76 case B134:
77 return 134;
78 case B150:
79 return 150;
80 case B200:
81 return 200;
82 case B300:
83 return 300;
84 case B600:
85 return 600;
86 case B1200:
87 return 1200;
88 case B1800:
89 return 1800;
90 case B2400:
91 return 2400;
92 case B4800:
93 return 4800;
94 case B9600:
95 return 9600;
96
97#ifdef B19200
98 case B19200:
99 return 19200;
100#else /* B19200 */
101#ifdef EXTA
102 case EXTA:
103 return 19200;
104#endif /* EXTA */
105#endif /* B19200 */
106
107#ifdef B38400
108 case B38400:
109 return 38400;
110#else /* B38400 */
111#ifdef EXTB
112 case EXTB:
113 return 38400;
114#endif /* EXTB */
115#endif /* B38400 */
116
117#ifdef B7200
118 case B7200:
119 return 7200;
120#endif /* B7200 */
121#ifdef B14400
122 case B14400:
123 return 14400;
124#endif /* B14400 */
125#ifdef B28800
126 case B28800:
127 return 28800;
128#endif /* B28800 */
129#ifdef B57600
130 case B57600:
131 return 57600;
132#endif /* B57600 */
133#ifdef B76800
134 case B76800:
135 return 76800;
136#endif /* B76800 */
137#ifdef B115200
138 case B115200:
139 return 115200;
140#endif /* B115200 */
141#ifdef B230400
142 case B230400:
143 return 230400;
144#endif /* B230400 */
145 default:
146 return 9600;
147 }
148}
149
150/*
151 * Converts a numeric baud rate to a POSIX speed_t.
152 */
153speed_t
154baud_to_speed(int baud)
155{
156 switch (baud) {
157 case 0:
158 return B0;
159 case 50:
160 return B50;
161 case 75:
162 return B75;
163 case 110:
164 return B110;
165 case 134:
166 return B134;
167 case 150:
168 return B150;
169 case 200:
170 return B200;
171 case 300:
172 return B300;
173 case 600:
174 return B600;
175 case 1200:
176 return B1200;
177 case 1800:
178 return B1800;
179 case 2400:
180 return B2400;
181 case 4800:
182 return B4800;
183 case 9600:
184 return B9600;
185
186#ifdef B19200
187 case 19200:
188 return B19200;
189#else /* B19200 */
190#ifdef EXTA
191 case 19200:
192 return EXTA;
193#endif /* EXTA */
194#endif /* B19200 */
195
196#ifdef B38400
197 case 38400:
198 return B38400;
199#else /* B38400 */
200#ifdef EXTB
201 case 38400:
202 return EXTB;
203#endif /* EXTB */
204#endif /* B38400 */
205
206#ifdef B7200
207 case 7200:
208 return B7200;
209#endif /* B7200 */
210#ifdef B14400
211 case 14400:
212 return B14400;
213#endif /* B14400 */
214#ifdef B28800
215 case 28800:
216 return B28800;
217#endif /* B28800 */
218#ifdef B57600
219 case 57600:
220 return B57600;
221#endif /* B57600 */
222#ifdef B76800
223 case 76800:
224 return B76800;
225#endif /* B76800 */
226#ifdef B115200
227 case 115200:
228 return B115200;
229#endif /* B115200 */
230#ifdef B230400
231 case 230400:
232 return B230400;
233#endif /* B230400 */
234 default:
235 return B9600;
236 }
237}
238
239/*
240 * Encode a special character into SSH line format.
241 */
242static u_int
243special_char_encode(cc_t c)
244{
245#ifdef _POSIX_VDISABLE
246 if (c == _POSIX_VDISABLE)
247 return 255;
248#endif /* _POSIX_VDISABLE */
249 return c;
250}
251
252/*
253 * Decode a special character from SSH line format.
254 */
255static cc_t
256special_char_decode(u_int c)
257{
258#ifdef _POSIX_VDISABLE
259 if (c == 255)
260 return _POSIX_VDISABLE;
261#endif /* _POSIX_VDISABLE */
262 return c;
263}
264
265#if 0 /* begin code ignore */
266
267/*
268 * Encodes terminal modes for the terminal referenced by fd
269 * or tiop in a portable manner, and appends the modes to a packet
270 * being constructed.
271 */
272void
273tty_make_modes(int fd, struct termios *tiop)
274{
275 struct termios tio;
276 int baud;
277 Buffer buf;
278 int tty_op_ospeed, tty_op_ispeed;
279 void (*put_arg)(Buffer *, u_int);
280
281 buffer_init(&buf);
282 if (compat20) {
283 tty_op_ospeed = TTY_OP_OSPEED_PROTO2;
284 tty_op_ispeed = TTY_OP_ISPEED_PROTO2;
285 put_arg = buffer_put_int;
286 } else {
287 tty_op_ospeed = TTY_OP_OSPEED_PROTO1;
288 tty_op_ispeed = TTY_OP_ISPEED_PROTO1;
289 put_arg = (void (*)(Buffer *, u_int)) buffer_put_char;
290 }
291
292 if (tiop == NULL) {
293 if (fd == -1) {
294 debug("tty_make_modes: no fd or tio");
295 goto end;
296 }
297 if (tcgetattr(fd, &tio) == -1) {
298 logit("tcgetattr: %.100s", strerror(errno));
299 goto end;
300 }
301 } else
302 tio = *tiop;
303
304 /* Store input and output baud rates. */
305 baud = speed_to_baud(cfgetospeed(&tio));
306 buffer_put_char(&buf, tty_op_ospeed);
307 buffer_put_int(&buf, baud);
308 baud = speed_to_baud(cfgetispeed(&tio));
309 buffer_put_char(&buf, tty_op_ispeed);
310 buffer_put_int(&buf, baud);
311
312 /* Store values of mode flags. */
313#define TTYCHAR(NAME, OP) \
314 buffer_put_char(&buf, OP); \
315 put_arg(&buf, special_char_encode(tio.c_cc[NAME]));
316
317#define TTYMODE(NAME, FIELD, OP) \
318 buffer_put_char(&buf, OP); \
319 put_arg(&buf, ((tio.FIELD & NAME) != 0));
320
321#include "ttymodes.h"
322
323#undef TTYCHAR
324#undef TTYMODE
325
326end:
327 /* Mark end of mode data. */
328 buffer_put_char(&buf, TTY_OP_END);
329 if (compat20)
330 packet_put_string(buffer_ptr(&buf), buffer_len(&buf));
331 else
332 packet_put_raw(buffer_ptr(&buf), buffer_len(&buf));
333 buffer_free(&buf);
334}
335
336/*
337 * Decodes terminal modes for the terminal referenced by fd in a portable
338 * manner from a packet being read.
339 */
340void
341tty_parse_modes(int fd, int *n_bytes_ptr)
342{
343 struct termios tio;
344 int opcode, baud;
345 int n_bytes = 0;
346 int failure = 0;
347 u_int (*get_arg)(void);
348 int arg_size;
349
350 if (compat20) {
351 *n_bytes_ptr = packet_get_int();
352 if (*n_bytes_ptr == 0)
353 return;
354 get_arg = packet_get_int;
355 arg_size = 4;
356 } else {
357 get_arg = packet_get_char;
358 arg_size = 1;
359 }
360
361 /*
362 * Get old attributes for the terminal. We will modify these
363 * flags. I am hoping that if there are any machine-specific
364 * modes, they will initially have reasonable values.
365 */
366 if (tcgetattr(fd, &tio) == -1) {
367 logit("tcgetattr: %.100s", strerror(errno));
368 failure = -1;
369 }
370
371 for (;;) {
372 n_bytes += 1;
373 opcode = packet_get_char();
374 switch (opcode) {
375 case TTY_OP_END:
376 goto set;
377
378 /* XXX: future conflict possible */
379 case TTY_OP_ISPEED_PROTO1:
380 case TTY_OP_ISPEED_PROTO2:
381 n_bytes += 4;
382 baud = packet_get_int();
383 if (failure != -1 &&
384 cfsetispeed(&tio, baud_to_speed(baud)) == -1)
385 error("cfsetispeed failed for %d", baud);
386 break;
387
388 /* XXX: future conflict possible */
389 case TTY_OP_OSPEED_PROTO1:
390 case TTY_OP_OSPEED_PROTO2:
391 n_bytes += 4;
392 baud = packet_get_int();
393 if (failure != -1 &&
394 cfsetospeed(&tio, baud_to_speed(baud)) == -1)
395 error("cfsetospeed failed for %d", baud);
396 break;
397
398#define TTYCHAR(NAME, OP) \
399 case OP: \
400 n_bytes += arg_size; \
401 tio.c_cc[NAME] = special_char_decode(get_arg()); \
402 break;
403#define TTYMODE(NAME, FIELD, OP) \
404 case OP: \
405 n_bytes += arg_size; \
406 if (get_arg()) \
407 tio.FIELD |= NAME; \
408 else \
409 tio.FIELD &= ~NAME; \
410 break;
411
412#include "ttymodes.h"
413
414#undef TTYCHAR
415#undef TTYMODE
416
417 default:
418 debug("Ignoring unsupported tty mode opcode %d (0x%x)",
419 opcode, opcode);
420 if (!compat20) {
421 /*
422 * SSH1:
423 * Opcodes 1 to 127 are defined to have
424 * a one-byte argument.
425 * Opcodes 128 to 159 are defined to have
426 * an integer argument.
427 */
428 if (opcode > 0 && opcode < 128) {
429 n_bytes += 1;
430 (void) packet_get_char();
431 break;
432 } else if (opcode >= 128 && opcode < 160) {
433 n_bytes += 4;
434 (void) packet_get_int();
435 break;
436 } else {
437 /*
438 * It is a truly undefined opcode (160 to 255).
439 * We have no idea about its arguments. So we
440 * must stop parsing. Note that some data
441 * may be left in the packet; hopefully there
442 * is nothing more coming after the mode data.
443 */
444 logit("parse_tty_modes: unknown opcode %d",
445 opcode);
446 goto set;
447 }
448 } else {
449 /*
450 * SSH2:
451 * Opcodes 1 to 159 are defined to have
452 * a uint32 argument.
453 * Opcodes 160 to 255 are undefined and
454 * cause parsing to stop.
455 */
456 if (opcode > 0 && opcode < 160) {
457 n_bytes += 4;
458 (void) packet_get_int();
459 break;
460 } else {
461 logit("parse_tty_modes: unknown opcode %d",
462 opcode);
463 goto set;
464 }
465 }
466 }
467 }
468
469set:
470 if (*n_bytes_ptr != n_bytes) {
471 *n_bytes_ptr = n_bytes;
472 logit("parse_tty_modes: n_bytes_ptr != n_bytes: %d %d",
473 *n_bytes_ptr, n_bytes);
474 return; /* Don't process bytes passed */
475 }
476 if (failure == -1)
477 return; /* Packet parsed ok but tcgetattr() failed */
478
479 /* Set the new modes for the terminal. */
480 if (tcsetattr(fd, TCSANOW, &tio) == -1)
481 logit("Setting tty modes failed: %.100s", strerror(errno));
482}
483
484#endif /* begin code ignore */
diff --git a/src/ttymodes.h b/src/ttymodes.h
new file mode 100644
index 0000000..4d848fe
--- /dev/null
+++ b/src/ttymodes.h
@@ -0,0 +1,175 @@
1/* $OpenBSD: ttymodes.h,v 1.14 2006/03/25 22:22:43 djm Exp $ */
2
3/*
4 * Author: Tatu Ylonen <ylo@cs.hut.fi>
5 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
6 * All rights reserved
7 *
8 * As far as I am concerned, the code I have written for this software
9 * can be used freely for any purpose. Any derived versions of this
10 * software must be clearly marked as such, and if the derived work is
11 * incompatible with the protocol description in the RFC file, it must be
12 * called by a name other than "ssh" or "Secure Shell".
13 */
14
15/*
16 * SSH2 tty modes support by Kevin Steves.
17 * Copyright (c) 2001 Kevin Steves. All rights reserved.
18 *
19 * Redistribution and use in source and binary forms, with or without
20 * modification, are permitted provided that the following conditions
21 * are met:
22 * 1. Redistributions of source code must retain the above copyright
23 * notice, this list of conditions and the following disclaimer.
24 * 2. Redistributions in binary form must reproduce the above copyright
25 * notice, this list of conditions and the following disclaimer in the
26 * documentation and/or other materials provided with the distribution.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
29 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
30 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
31 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
32 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
33 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
34 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
35 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
36 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
37 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38 */
39
40/*
41 * SSH1:
42 * The tty mode description is a stream of bytes. The stream consists of
43 * opcode-arguments pairs. It is terminated by opcode TTY_OP_END (0).
44 * Opcodes 1-127 have one-byte arguments. Opcodes 128-159 have integer
45 * arguments. Opcodes 160-255 are not yet defined, and cause parsing to
46 * stop (they should only be used after any other data).
47 *
48 * SSH2:
49 * Differences between SSH1 and SSH2 terminal mode encoding include:
50 * 1. Encoded terminal modes are represented as a string, and a stream
51 * of bytes within that string.
52 * 2. Opcode arguments are uint32 (1-159); 160-255 remain undefined.
53 * 3. The values for TTY_OP_ISPEED and TTY_OP_OSPEED are different;
54 * 128 and 129 vs. 192 and 193 respectively.
55 *
56 * The client puts in the stream any modes it knows about, and the
57 * server ignores any modes it does not know about. This allows some degree
58 * of machine-independence, at least between systems that use a posix-like
59 * tty interface. The protocol can support other systems as well, but might
60 * require reimplementing as mode names would likely be different.
61 */
62
63/*
64 * Some constants and prototypes are defined in packet.h; this file
65 * is only intended for including from ttymodes.c.
66 */
67
68/* termios macro */
69/* name, op */
70TTYCHAR(VINTR, 1)
71TTYCHAR(VQUIT, 2)
72TTYCHAR(VERASE, 3)
73#if defined(VKILL)
74TTYCHAR(VKILL, 4)
75#endif /* VKILL */
76TTYCHAR(VEOF, 5)
77#if defined(VEOL)
78TTYCHAR(VEOL, 6)
79#endif /* VEOL */
80#ifdef VEOL2
81TTYCHAR(VEOL2, 7)
82#endif /* VEOL2 */
83TTYCHAR(VSTART, 8)
84TTYCHAR(VSTOP, 9)
85#if defined(VSUSP)
86TTYCHAR(VSUSP, 10)
87#endif /* VSUSP */
88#if defined(VDSUSP)
89TTYCHAR(VDSUSP, 11)
90#endif /* VDSUSP */
91#if defined(VREPRINT)
92TTYCHAR(VREPRINT, 12)
93#endif /* VREPRINT */
94#if defined(VWERASE)
95TTYCHAR(VWERASE, 13)
96#endif /* VWERASE */
97#if defined(VLNEXT)
98TTYCHAR(VLNEXT, 14)
99#endif /* VLNEXT */
100#if defined(VFLUSH)
101TTYCHAR(VFLUSH, 15)
102#endif /* VFLUSH */
103#ifdef VSWTCH
104TTYCHAR(VSWTCH, 16)
105#endif /* VSWTCH */
106#if defined(VSTATUS)
107TTYCHAR(VSTATUS, 17)
108#endif /* VSTATUS */
109#ifdef VDISCARD
110TTYCHAR(VDISCARD, 18)
111#endif /* VDISCARD */
112
113/* name, field, op */
114TTYMODE(IGNPAR, c_iflag, 30)
115TTYMODE(PARMRK, c_iflag, 31)
116TTYMODE(INPCK, c_iflag, 32)
117TTYMODE(ISTRIP, c_iflag, 33)
118TTYMODE(INLCR, c_iflag, 34)
119TTYMODE(IGNCR, c_iflag, 35)
120TTYMODE(ICRNL, c_iflag, 36)
121#if defined(IUCLC)
122TTYMODE(IUCLC, c_iflag, 37)
123#endif
124TTYMODE(IXON, c_iflag, 38)
125TTYMODE(IXANY, c_iflag, 39)
126TTYMODE(IXOFF, c_iflag, 40)
127#ifdef IMAXBEL
128TTYMODE(IMAXBEL,c_iflag, 41)
129#endif /* IMAXBEL */
130
131TTYMODE(ISIG, c_lflag, 50)
132TTYMODE(ICANON, c_lflag, 51)
133#ifdef XCASE
134TTYMODE(XCASE, c_lflag, 52)
135#endif
136TTYMODE(ECHO, c_lflag, 53)
137TTYMODE(ECHOE, c_lflag, 54)
138TTYMODE(ECHOK, c_lflag, 55)
139TTYMODE(ECHONL, c_lflag, 56)
140TTYMODE(NOFLSH, c_lflag, 57)
141TTYMODE(TOSTOP, c_lflag, 58)
142#ifdef IEXTEN
143TTYMODE(IEXTEN, c_lflag, 59)
144#endif /* IEXTEN */
145#if defined(ECHOCTL)
146TTYMODE(ECHOCTL,c_lflag, 60)
147#endif /* ECHOCTL */
148#ifdef ECHOKE
149TTYMODE(ECHOKE, c_lflag, 61)
150#endif /* ECHOKE */
151#if defined(PENDIN)
152TTYMODE(PENDIN, c_lflag, 62)
153#endif /* PENDIN */
154
155TTYMODE(OPOST, c_oflag, 70)
156#if defined(OLCUC)
157TTYMODE(OLCUC, c_oflag, 71)
158#endif
159#ifdef ONLCR
160TTYMODE(ONLCR, c_oflag, 72)
161#endif
162#ifdef OCRNL
163TTYMODE(OCRNL, c_oflag, 73)
164#endif
165#ifdef ONOCR
166TTYMODE(ONOCR, c_oflag, 74)
167#endif
168#ifdef ONLRET
169TTYMODE(ONLRET, c_oflag, 75)
170#endif
171
172TTYMODE(CS7, c_cflag, 90)
173TTYMODE(CS8, c_cflag, 91)
174TTYMODE(PARENB, c_cflag, 92)
175TTYMODE(PARODD, c_cflag, 93)
diff --git a/src/util.c b/src/util.c
new file mode 100644
index 0000000..0a6a594
--- /dev/null
+++ b/src/util.c
@@ -0,0 +1,101 @@
1#include "common.h"
2#include <gnunet/gnunet_util_lib.h>
3#include "mshd.h"
4#include "util.h"
5
6#define LOG_STRERROR(cmd) \
7 GNUNET_log_from_strerror (GNUNET_ERROR_TYPE_WARNING, "mshd-util", cmd)
8
9
10/**
11 * Creates a new non-blocking socket and binds it to the given address and makes
12 * it a listen socket
13 *
14 * @param addr the address to bind to
15 * @param addrlen the length of the addr
16 * @param backlog the max length of the pending connections. This will be
17 * passed to listen()
18 * @return the handler to the socket; NULL upon error
19 */
20struct GNUNET_NETWORK_Handle *
21open_listen_socket (struct sockaddr *addr, const socklen_t addrlen, int backlog)
22{
23 struct GNUNET_NETWORK_Handle *lsock;
24 socklen_t newaddrlen;
25 int sockfd;
26
27 if (NULL == (lsock = GNUNET_NETWORK_socket_create (AF_INET, SOCK_STREAM, 0)))
28 {
29 GNUNET_break (0);
30 return NULL;
31 }
32 if (GNUNET_OK != GNUNET_NETWORK_socket_bind (lsock, addr, addrlen))
33 {
34 GNUNET_break (0);
35 goto clo_ret;
36 }
37 sockfd = GNUNET_NETWORK_get_fd (lsock);
38 newaddrlen = addrlen;
39 if (-1 == getsockname (sockfd, addr, &newaddrlen))
40 {
41 LOG_STRERROR ("getsockname");
42 goto clo_ret;
43 }
44 if (newaddrlen != addrlen)
45 {
46 GNUNET_break (0);
47 goto clo_ret;
48 }
49 if (GNUNET_OK != GNUNET_NETWORK_socket_listen (lsock, backlog))
50 {
51 GNUNET_break (0);
52 goto clo_ret;
53 }
54 return lsock;
55
56 clo_ret:
57 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (lsock));
58 return NULL;
59}
60
61
62/**
63 * Return the numeric ASCII representation of the given sockaddr
64 *
65 * @param addr the address to represent
66 * @param addrlen the length of the sockaddr structure
67 * @return the numeric ASCII representation
68 */
69const char *
70saddr2str (const struct sockaddr *addr, const socklen_t addrlen)
71{
72 static char hostip[NI_MAXHOST];
73
74 if (0 != getnameinfo (addr, addrlen, hostip, NI_MAXHOST, NULL, 0,
75 NI_NUMERICHOST))
76 {
77 LOG_STRERROR ("getnameinfo");
78 return NULL;
79 }
80 return hostip;
81}
82
83
84/**
85 * Function to convert an 32-bit IP address into numbers-and-dots notation
86 *
87 * @param ip the IP address
88 * @return the string represeting the IP address. The string is statically allocated.
89 */
90const char *
91ip2str (const in_addr_t ip)
92{
93 static char hostip[NI_MAXHOST];
94
95 GNUNET_break (0 < snprintf (hostip, NI_MAXHOST, "%u.%u.%u.%u",
96 ip >> 24,
97 (ip >> 16) % 256,
98 (ip >> 8) % 256,
99 ip % 256));
100 return hostip;
101}
diff --git a/src/util.h b/src/util.h
new file mode 100644
index 0000000..dcb1b8d
--- /dev/null
+++ b/src/util.h
@@ -0,0 +1,43 @@
1#ifndef MSH_UTIL_H
2#define MSH_UTIL_H
3
4#include <gnunet/gnunet_common.h>
5
6
7/**
8 * Creates a new non-blocking socket and binds it to the given address and makes
9 * it a listen socket
10 *
11 * @param addr the address to bind to
12 * @param addrlen the length of the addr
13 * @param backlog the max length of the pending connections. This will be
14 * passed to listen()
15 * @return the handler to the socket; NULL upon error
16 */
17struct GNUNET_NETWORK_Handle *
18open_listen_socket (struct sockaddr *addr, const socklen_t addrlen, int backlog);
19
20
21/**
22 * Return the numeric ASCII representation of the given sockaddr
23 *
24 * @param addr the address to represent
25 * @param addrlen the length of the sockaddr structure
26 * @return the numeric ASCII representation
27 */
28const char *
29saddr2str (const struct sockaddr *addr, const socklen_t addrlen);
30
31
32/**
33 * Function to convert an 32-bit IP address into numbers-and-dots notation
34 *
35 * @param ip the IP address
36 * @return the string represeting the IP address. The string is statically allocated.
37 */
38const char *
39ip2str (const in_addr_t ip);
40
41
42#endif /* #ifndef MSH_UTIL_H */
43/* end of MSH_UTIL_H */