diff options
-rw-r--r-- | Makefile.am | 2 | ||||
-rw-r--r-- | README | 48 | ||||
-rwxr-xr-x | bootstrap | 1 | ||||
-rw-r--r-- | configure.ac | 105 | ||||
-rw-r--r-- | doc/.latexmkrc | 15 | ||||
-rw-r--r-- | doc/Makefile | 45 | ||||
-rw-r--r-- | doc/fig/svg/ip_map.svg | 280 | ||||
-rw-r--r-- | doc/fig/svg/job_startup.svg | 520 | ||||
-rw-r--r-- | doc/msh.tex | 368 | ||||
-rw-r--r-- | doc/related_work.bib | 1466 | ||||
-rw-r--r-- | src/Makefile.am | 40 | ||||
-rw-r--r-- | src/addressmap.c | 764 | ||||
-rw-r--r-- | src/addressmap.h | 329 | ||||
-rw-r--r-- | src/bitmap.c | 159 | ||||
-rw-r--r-- | src/bitmap.h | 80 | ||||
-rw-r--r-- | src/common.h | 39 | ||||
-rw-r--r-- | src/launch.c | 44 | ||||
-rw-r--r-- | src/launch_ll.c | 47 | ||||
-rw-r--r-- | src/mping.c | 424 | ||||
-rw-r--r-- | src/msh.c | 938 | ||||
-rw-r--r-- | src/msh_waiter.c | 392 | ||||
-rw-r--r-- | src/mshd.c | 1550 | ||||
-rw-r--r-- | src/mshd.h | 44 | ||||
-rw-r--r-- | src/mshd2.c | 1297 | ||||
-rw-r--r-- | src/mtypes.h | 317 | ||||
-rw-r--r-- | src/pmonitor.c | 314 | ||||
-rw-r--r-- | src/pmonitor.h | 90 | ||||
-rw-r--r-- | src/prop.c | 17 | ||||
-rw-r--r-- | src/reduce.c | 121 | ||||
-rw-r--r-- | src/reduce.h | 21 | ||||
-rwxr-xr-x | src/run.sh | 6 | ||||
-rw-r--r-- | src/server.c | 1248 | ||||
-rw-r--r-- | src/server.h | 56 | ||||
-rw-r--r-- | src/test_addressmap.c | 164 | ||||
-rw-r--r-- | src/test_bitmap.c | 54 | ||||
-rwxr-xr-x | src/test_mping.sh | 12 | ||||
-rw-r--r-- | src/test_pty.c | 666 | ||||
-rw-r--r-- | src/ttymodes.c | 484 | ||||
-rw-r--r-- | src/ttymodes.h | 175 | ||||
-rw-r--r-- | src/util.c | 101 | ||||
-rw-r--r-- | src/util.h | 43 |
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 | ||
2 | SUBDIRS = src \ No newline at end of file | ||
@@ -0,0 +1,48 @@ | |||
1 | MPI-Shell (MSH) is a remote shell for executing commands remotely on hosts where | ||
2 | Message Passing Interface (MPI) layer is available for communication. Such | ||
3 | hosts are commonly found in High Performance Computing (HPC) systems such as | ||
4 | compute clusters or supercomputers. | ||
5 | |||
6 | The motivation for this project is that often in such systems Secure-Shell (SSH) | ||
7 | is either unavailable or restricted for users due to security reasons. As a | ||
8 | result, hosts in these systems cannot be used for non MPI applications such as | ||
9 | network emulators or testbeds which rely on SSH to establish connections among | ||
10 | the hosts. MSH aims to solve this problem by providing an alternative remote | ||
11 | shell which can be used by these applications instead of SSH. | ||
12 | |||
13 | Architecture | ||
14 | ------------ | ||
15 | |||
16 | MSH consists of two components: the MSH daemon(mshd) and the MSH client. mshd | ||
17 | is similar to SSH daemon(ssd) in that one mshd instance is started per host. | ||
18 | The daemons execute the commands given from remote MSH clients. However, unlike | ||
19 | sshd, mshd is started by the job scheduler employed in the HPC system and only | ||
20 | runs during the life-time of the job. | ||
21 | |||
22 | |||
23 | The MSH client, takes the IP address of the target host and the | ||
24 | remote command string as arguments. The client relies on the local | ||
25 | mshd for learning the port address of the remote mshd and for | ||
26 | authenticating itself to the remote mshd. | ||
27 | |||
28 | The command string is executed by the remote mshd after successful | ||
29 | authentication of the connecting MSH client. The input for the executed command | ||
30 | string is relayed by the MSH client to the remote mshd. Similarly, the output | ||
31 | from the executed command string is relayed from the remote mshd to the MSH | ||
32 | client; | ||
33 | |||
34 | Installation | ||
35 | ------------ | ||
36 | |||
37 | Installation should be fairly simple if you want to go-ahead with the default | ||
38 | settings. The following steps should do the job: | ||
39 | |||
40 | $ ./bootstrap | ||
41 | $ ./configure | ||
42 | $ make | ||
43 | $ make install | ||
44 | |||
45 | You may change some of the default settings before installing via ./configure. | ||
46 | For 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 | |||
5 | AC_PREREQ([2.69]) | ||
6 | AC_INIT([msh], [0.0.0], [totakura@in.tum.de]) | ||
7 | AM_INIT_AUTOMAKE([foreign -Wall -Werror]) | ||
8 | dnl m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) | ||
9 | AC_CONFIG_SRCDIR([src/mshd.c]) | ||
10 | AC_CONFIG_HEADERS([config.h]) | ||
11 | |||
12 | # Checks for programs. | ||
13 | CC="" | ||
14 | AC_PROG_CC([mpicc]) | ||
15 | AM_PROG_CC_C_O dnl allow per target automake flags | ||
16 | |||
17 | # Checks for header files. | ||
18 | AC_CHECK_HEADERS([stdlib.h string.h unistd.h netinet/in.h net/if.h ifaddrs.h \ | ||
19 | sys/socket.h sys/select.h sys/time.h sys/types.h error.h errno.h limits.h \ | ||
20 | regex.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. | ||
26 | AC_FUNC_MALLOC | ||
27 | AC_FUNC_REALLOC | ||
28 | AC_CHECK_FUNCS([strdup strlen strerror strcmp getnameinfo getifaddrs freeifaddrs \ | ||
29 | printf fprintf snprintf vsnprintf memset gettimeofday localtime strftime \ | ||
30 | getpid getcwd],, | ||
31 | [AC_MSG_ERROR([a required C library function is missing])]) | ||
32 | |||
33 | # test for math functions | ||
34 | AC_CHECK_HEADERS([math.h], | ||
35 | [AC_CHECK_LIB([m], [log])]) | ||
36 | AC_CHECK_FUNC([ceil],math=1) | ||
37 | if test "$math" != 1 | ||
38 | then | ||
39 | AC_MSG_ERROR([MSH requires math library]) | ||
40 | fi | ||
41 | |||
42 | # test for mpi | ||
43 | AC_CHECK_HEADERS([mpi.h], [AC_CHECK_LIB([mpi], [MPI_Init], [mpi=1])]) | ||
44 | if test "$mpi" != 1 | ||
45 | then | ||
46 | AC_MSG_ERROR([MSH requires MPI libraries]) | ||
47 | fi | ||
48 | |||
49 | # test for libgnunetutil | ||
50 | libgnunetutil=0 | ||
51 | AC_MSG_CHECKING(for libgnunetutil) | ||
52 | AC_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 | ]) | ||
94 | if test "$libgnunetutil" != 1 | ||
95 | then | ||
96 | AC_MSG_ERROR([MSH requires gnunet]) | ||
97 | fi | ||
98 | |||
99 | dnl have all messages as of now | ||
100 | extra_logging=1; | ||
101 | AC_DEFINE_UNQUOTED([GNUNET_EXTRA_LOGGING],[$extra_logging],[1 if extra logging is enabled, 2 for very verbose extra logging, 0 otherwise]) | ||
102 | |||
103 | AC_CONFIG_FILES([Makefile | ||
104 | src/Makefile]) | ||
105 | AC_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 @@ | |||
1 | add_cus_dep('glo', 'gls', 0, 'run_makeglossaries'); | ||
2 | add_cus_dep('acn', 'acr', 0, 'run_makeglossaries'); | ||
3 | |||
4 | sub run_makeglossaries { | ||
5 | if ( $silent ) { | ||
6 | system "makeglossaries -q '$_[0]'"; | ||
7 | } | ||
8 | else { | ||
9 | system "makeglossaries '$_[0]'"; | ||
10 | }; | ||
11 | } | ||
12 | |||
13 | push @generated_exts, 'glo', 'gls', 'glg'; | ||
14 | push @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 @@ | |||
1 | MAINFILE := msh | ||
2 | DIA := $(shell find . -iname '*.dia') | ||
3 | DOT := $(shell find . -iname '*.dot') | ||
4 | SVG := $(shell find ./fig/svg -iname '*.svg') | ||
5 | GNUPLOT := $(shell find . -iname '*.gnuplot') | ||
6 | VIEWERAPP := xdg-open | ||
7 | |||
8 | .PHONY: all pdf clean view | ||
9 | all: \ | ||
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 | |||
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 | |||
32 | pdf: | ||
33 | latexmk -r .latexmkrc -silent -pdf $(MAINFILE) | ||
34 | |||
35 | view: all | ||
36 | $(VIEWERAPP) $(MAINFILE).pdf & | ||
37 | |||
38 | presentation: \ | ||
39 | |||
40 | clean: | ||
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} | ||
59 | Large scale network experimentation of distributed systems is achieved by | ||
60 | distributing the experiment across multiple physical nodes~\cite{dpeersim, wids, | ||
61 | netlab, cset2011evans, totakura2013ms}. These tools coordinate the experiment | ||
62 | among the hosts by establishing SSH connections to run remote commands on the | ||
63 | available hosts. | ||
64 | |||
65 | A limiting factor in scaling network experiments in the availability of | ||
66 | computing power and underlying network. This requirement for resources can be | ||
67 | addressed by running network experiments on High Performance Computing (HPC) | ||
68 | systems which are made up of many hosts interconnected with a high speed and | ||
69 | high bandwidth network. | ||
70 | |||
71 | The usage of HPC systems poses some new challenges: since HPC systems are used | ||
72 | by multiple users simultaneously, they allocate exclusive resources dynamically. | ||
73 | The user has to determine these dynamically allocated resources before starting | ||
74 | the experiment on these resources. The \textit{de-facto} standard for remote | ||
75 | command execution, SSH, is increasingly made unavailable or restricted on HPC | ||
76 | systems~\cite{supermuc} to prevent users from accessing resources which are not | ||
77 | allocated to them. While such restriction does not effect the intended usage of | ||
78 | HPC systems which is to run parallel programs with Message Passing Interface | ||
79 | (MPI) for communications, it presents users to use network experimentation tools | ||
80 | which rely on remote command execution. | ||
81 | |||
82 | To overcome these challenges we propose, MSH, a new remote command execution | ||
83 | system which uses MPI for determining node allocation and addressing. Our aims | ||
84 | are: to provide MSH as a substitute for SSH for remote command execution; to | ||
85 | make MSH behave similar to SSH such that the network experimentation tools do | ||
86 | not have to be heavily modified; to determine the dynamically allocated | ||
87 | resources on the HPC system and, finally, to be able to run network experiments | ||
88 | on HPC systems. | ||
89 | |||
90 | \section{Architecture} | ||
91 | |||
92 | MSH consists of two components: the \texttt{mshd} daemon and the \texttt{msh} | ||
93 | client. \texttt{mshd} is similar to \texttt{sshd} in that one \texttt{mshd} | ||
94 | daemon per host is started. The daemons execute the commands given from remote | ||
95 | \texttt{msh} clients. However, unlike \texttt{sshd}, \texttt{mshd} is started | ||
96 | by the job scheduler and only runs during the job. | ||
97 | |||
98 | The MSH client, \texttt{msh}, takes the IP address of the target host and the | ||
99 | remote command string as arguments. The client relies on the local | ||
100 | \texttt{mshd} for learning the address of the remote \texttt{mshd} and | ||
101 | authenticating itself to the remote \texttt{mshd}. | ||
102 | |||
103 | The command string is executed by the remote \texttt{mshd} after successful | ||
104 | authentication of \texttt{msh}. The input for the executed command string is | ||
105 | relayed by \texttt{msh} to the remote \texttt{mshd}. Similarly, the output from | ||
106 | the 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 | |||
116 | An overview of the interactions involved in starting an application with MSH is | ||
117 | shown 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 | |||
158 | One of our aims is to determine the resources which are dynamically allocated to | ||
159 | us and provide their details to the experimentation tools. Since we intend to | ||
160 | use MSH as a substitute for SSH, we provide the resources' IP addresses so that | ||
161 | the tools can refer to these resources by IP addresses. | ||
162 | |||
163 | The mapping between the allocated hosts and their IP addresses is determined by | ||
164 | having each \texttt{mshd} instance verify the IP addresses of all other | ||
165 | \texttt{mshd} instances running on the allocated hosts. The verification | ||
166 | proceeds in rounds where each instance verifies IP addresses of several | ||
167 | instances. At the beginning of each round, every instance opens a socket bound | ||
168 | to a random port and all available IP addresses on its host and sends the IP | ||
169 | addresses to a set of instances $\mathbb{N}$ for verification. The set | ||
170 | $\mathbb{N}$ is determined from the set of all instances $\mathbb{I}$ | ||
171 | depending 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} | ||
175 | The instances verify the IP addresses of the sending instance by establishing | ||
176 | TCP connections to the sender's listening socket with one TCP connection for | ||
177 | each of the sender's IP addresses. The TCP connections are started in parallel | ||
178 | and 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 | |||
187 | At the end of the last round, all instances would have verified the IP | ||
188 | addresses of other instances and posses an instance-to-IP mapping. At this point, | ||
189 | they accumulate their mappings using a reduction algorithm (binary/ binomial | ||
190 | tree reduction). The reduction is made by intersecting the reported IP | ||
191 | addresses for an instance. | ||
192 | |||
193 | \section{Limitations} | ||
194 | MSH does not have terminal handling capabilities yet. This means that | ||
195 | applications such as \texttt{screen}, \texttt{less}, \texttt{vim} which require | ||
196 | terminal (\texttt{tty}) support do not work through MSH. This also means that | ||
197 | there 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} | ||
202 | This chapter provides information for the installation of MSH and its usage. We | ||
203 | provide examples which showcase how MSH is used in experiments conducted on HPC | ||
204 | systems. | ||
205 | |||
206 | \section{Installation} | ||
207 | The source code for MSH is available from our Subversion repository:\\ | ||
208 | \url{https://gnunet.org/svn/msh/}. | ||
209 | |||
210 | MSH depends on GNUnet's networking API and hence requires | ||
211 | GNUnet\footnote{\url{https://gnunet.org/}} to be installed. GNUnet sources can | ||
212 | be downloaded from its repository at \url{https://gnunet.org/svn/gnunet/}. | ||
213 | Additionally, it requires an MPI implementation to be installed together with | ||
214 | the MPI compiler wrapper \texttt{mpicc}. Note that the repositories for MSH and | ||
215 | GNUnet are used for active development and hence checking out the current | ||
216 | versions may sometimes break the stability of MSH or simply may not compile. | ||
217 | The 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 | |||
220 | Once the dependencies are installed, MSH can be installed by running the | ||
221 | commands 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 | |||
228 | If the required dependencies are not in the default search paths of the | ||
229 | compiler, \texttt{configure} may fail complaining an error. These can be fixed | ||
230 | by 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} | ||
236 | MSH is started by running the MSH daemon on the available nodes through the MPI | ||
237 | execution wrappers. The available nodes are determined either manually and | ||
238 | given to the execution wrapper as a hostlist file (as in the case with small | ||
239 | group of systems or clusters) or dynamically by either a job scheduling system | ||
240 | such as LoadLeveler\cite{prenneis1996loadleveler} or SLURM\cite{yoo2003slurm}. | ||
241 | The execution wrappers can be started as an interactive job or as a batch job. | ||
242 | Interactive job execution gives more control to the user as the user can | ||
243 | directly interact with the job through the job's standard input and output. | ||
244 | Batch job execution allows for the job to be queued in a batch scheduling system | ||
245 | which executes the job whenever the required number of resources are available. | ||
246 | |||
247 | Since only one MSH daemon should run on each host, the wrappers are configured | ||
248 | with the respective parameters such that they start only one instance of MSH per | ||
249 | host. | ||
250 | |||
251 | Examples for starting MSH on various HPC systems are shown in the following | ||
252 | listings. \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 | |||
260 | Listing~\ref{lst:slurm_interactive} shows interactive MSH startup on an MPI | ||
261 | cluster. The cluster uses SLURM for job scheduling. The command | ||
262 | \texttt{salloc} in line 1 is used to allocate resources. Here we allocate 3 | ||
263 | nodes from the cluster partition \texttt{mpp1\_inter} and configure the MPI | ||
264 | execution wrapper to run 1 MPI process per node. When the allocation is | ||
265 | successful, \texttt{mshd} is launched in line 2 with the command | ||
266 | \texttt{srun\_ps} which is specific to SLURM for launching MPI programs. When | ||
267 | MSH 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 | |||
277 | Listing~\ref{lst:ll_interactive} shows interactive MSH startup on SuperMUC using | ||
278 | the LoadLeveler scheduler. In lines 1, 2 we specify that we want to allocate 3 | ||
279 | nodes for our experiment and only one instance of \texttt{mshd} has to be | ||
280 | started on each of them. In line 3, we start \texttt{mshd} processes through | ||
281 | the LoadLeveler's \texttt{poe} command. | ||
282 | |||
283 | \section{Using MSH} | ||
284 | \label{sec:using} | ||
285 | |||
286 | The usage of MSH is aimed at HPC systems where remote shells are disabled and | ||
287 | MPI is available. With MSH, we address two problems: 1. we facilitate remote | ||
288 | command execution and 2. we provide an easy interface to learn which hosts are | ||
289 | allocated to the job by listing their addresses. | ||
290 | |||
291 | The IP addresses of the hosts are made available as hostlist file to the | ||
292 | processes \texttt{mshd} processes start. The path of this hostlist file is made | ||
293 | available through the environmental variable \texttt{MP\_SAVEHOSTFILE}. | ||
294 | \texttt{msh} can be used to connect to any of the hosts listed in this file. | ||
295 | Listing~\ref{lst:msh_connect} shows an example for connecting to the allocated | ||
296 | hosts. 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 | ||
303 | 10.0.0.3 | ||
304 | 10.0.0.4 | ||
305 | 10.0.0.5 | ||
306 | $ msh 10.0.0.4 date | ||
307 | Fri Sep 6 11:17:09 CEST 2013 | ||
308 | $ quit | ||
309 | \end{lstlisting} | ||
310 | |||
311 | MSH can also be used by programs which are started by \texttt{mshd} instances. | ||
312 | The programs however should take care to read the addresses of allocated hosts | ||
313 | from the hostlist file from the evironmental variable and use \texttt{msh} for | ||
314 | executing remote commands on those hosts. | ||
315 | |||
316 | In our experiments, our distributed testbed~\cite{totakura2013ms} determines the | ||
317 | allocated hosts through the hostfile and uses \texttt{msh} to spawn controllers | ||
318 | for 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 | ||
320 | root \texttt{mshd} instance is running. | ||
321 | Listing~\ref{slurm_interactive_testbed_startup} shows the commands used to start | ||
322 | the testbed. In the same way, other simulation and emulation software for | ||
323 | network experiments which rely on SSH for starting remote processes can use MSH | ||
324 | as 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 | |||
333 | On a system with LoadLeveler such as SuperMUC the above experiment startup is | ||
334 | shown 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 | |||
348 | Termination in MSH can be divided into two parts: the termination of remote | ||
349 | access 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 | ||
353 | is complete and all the output from the command is fetched from the remote | ||
354 | host. 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 | ||
356 | not found on the remote host and if the local \texttt{msh} processes receives | ||
357 | any of the termination (SIGTERM, SIGINT) signals. | ||
358 | |||
359 | The \texttt{mshd} processes terminate successfully when the main process started | ||
360 | by the root \texttt{mshd} processes terminates. They terminate with error if | ||
361 | the main process crashes or terminates with error, or if the binary needed for | ||
362 | launching 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 | |||
12 | In 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 | |||
14 | To 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 | |||
16 | We 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 | ||
2 | bin_PROGRAMS = mping mshd msh test-pty msh-waiter | ||
3 | |||
4 | mping_SOURCES = mping.c | ||
5 | |||
6 | mshd_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 | ||
10 | mshd_LDADD = -lgnunetutil -lm | ||
11 | |||
12 | msh_SOURCES = msh.c mtypes.h ttymodes.c ttymodes.h | ||
13 | msh_LDADD = -lgnunetutil util.$(OBJEXT) | ||
14 | |||
15 | check_PROGRAMS = \ | ||
16 | test-bitmap \ | ||
17 | test-addressmap | ||
18 | |||
19 | test_bitmap_SOURCES = test_bitmap.c | ||
20 | test_bitmap_LDADD = -lgnunetutil bitmap.$(OBJEXT) | ||
21 | |||
22 | test_addressmap_SOURCES = test_addressmap.c | ||
23 | test_addressmap_LDADD = -lgnunetutil addressmap.$(OBJEXT) util.$(OBJEXT) | ||
24 | |||
25 | TESTS = \ | ||
26 | test-bitmap \ | ||
27 | test-addressmap | ||
28 | |||
29 | noinst_PROGRAMS = prop launch | ||
30 | prop_SOURCES = prop.c | ||
31 | prop_LDADD = -lgnunetutil | ||
32 | |||
33 | launch_SOURCES = launch.c | ||
34 | launch_LDADD = -lgnunetutil | ||
35 | |||
36 | test_pty_SOURCES = test_pty.c mtyes.h ttymodes.h ttymodes.c | ||
37 | test_pty_LDADD = -lgnunetutil | ||
38 | |||
39 | msh_waiter_SOURCES = msh_waiter.c mtypes.h ttymodes.h ttymodes.c | ||
40 | msh_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 | */ | ||
23 | struct 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 | */ | ||
50 | struct 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 | */ | ||
93 | uint16_t | ||
94 | instance_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 | */ | ||
106 | struct InstanceAddr * | ||
107 | instance_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 | */ | ||
123 | void | ||
124 | instance_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 | */ | ||
136 | struct InstanceAddrInfo * | ||
137 | instance_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 | */ | ||
156 | int | ||
157 | instance_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 | */ | ||
191 | int | ||
192 | instance_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 | */ | ||
218 | unsigned int | ||
219 | instance_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 | */ | ||
231 | void | ||
232 | instance_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 | */ | ||
253 | struct 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 | */ | ||
274 | AddressMap * | ||
275 | addressmap_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 | */ | ||
297 | int | ||
298 | addressmap_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 | */ | ||
329 | int | ||
330 | addressmap_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 | */ | ||
391 | int | ||
392 | addressmap_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 | */ | ||
421 | int | ||
422 | addressmap_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 | */ | ||
442 | void | ||
443 | addressmap_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 | */ | ||
468 | int | ||
469 | addressmap_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 | */ | ||
529 | int | ||
530 | addressmap_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 | */ | ||
573 | void | ||
574 | addressmap_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 | */ | ||
602 | int | ||
603 | addressmap_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 | */ | ||
638 | struct 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 | */ | ||
655 | static int | ||
656 | reversemap_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 | */ | ||
685 | static int | ||
686 | reversemap_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 | */ | ||
702 | struct ReverseAddressMap * | ||
703 | addressmap_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 | */ | ||
724 | void | ||
725 | reverse_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 | */ | ||
744 | int | ||
745 | reversemap_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 | */ | ||
760 | struct InstanceAddr * | ||
761 | reversemap_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 | */ | ||
16 | struct InstanceAddr; | ||
17 | |||
18 | |||
19 | /** | ||
20 | * Instance address information | ||
21 | */ | ||
22 | struct 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 | */ | ||
32 | struct InstanceAddr * | ||
33 | instance_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 | */ | ||
42 | uint16_t | ||
43 | instance_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 | */ | ||
52 | struct InstanceAddrInfo * | ||
53 | instance_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 | */ | ||
61 | void | ||
62 | instance_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 | */ | ||
74 | int | ||
75 | instance_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 | */ | ||
85 | unsigned int | ||
86 | instance_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 | */ | ||
95 | void | ||
96 | instance_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 | */ | ||
108 | typedef 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 | */ | ||
122 | int | ||
123 | instance_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 | */ | ||
132 | typedef 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 | */ | ||
141 | AddressMap * | ||
142 | addressmap_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 | */ | ||
151 | void | ||
152 | addressmap_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 | */ | ||
166 | int | ||
167 | addressmap_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 | */ | ||
178 | int | ||
179 | addressmap_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 | */ | ||
190 | typedef 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 | */ | ||
204 | int | ||
205 | addressmap_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 | */ | ||
221 | int | ||
222 | addressmap_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 | */ | ||
238 | int | ||
239 | addressmap_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 | */ | ||
252 | int | ||
253 | addressmap_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 | */ | ||
262 | void | ||
263 | addressmap_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 | */ | ||
273 | int | ||
274 | addressmap_write_hosts (AddressMap *m, const char *fn); | ||
275 | |||
276 | |||
277 | /** | ||
278 | * Handle for reverse mapping from IP addresses to instance addresses | ||
279 | */ | ||
280 | struct 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 | */ | ||
289 | struct ReverseAddressMap * | ||
290 | addressmap_create_reverse_mapping (AddressMap *m); | ||
291 | |||
292 | |||
293 | /** | ||
294 | * Destroy a reverse address map | ||
295 | * | ||
296 | * @param rmap the reverse address map | ||
297 | */ | ||
298 | void | ||
299 | reverse_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 | */ | ||
310 | int | ||
311 | reversemap_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 | */ | ||
323 | struct InstanceAddr * | ||
324 | reversemap_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 | */ | ||
13 | struct 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 | */ | ||
40 | struct BitMap * | ||
41 | bitmap_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 | */ | ||
60 | void | ||
61 | bitmap_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 | */ | ||
72 | void | ||
73 | bitmap_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 | */ | ||
86 | void | ||
87 | bitmap_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 | */ | ||
114 | int | ||
115 | bitmap_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 | */ | ||
136 | int | ||
137 | bitmap_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 | */ | ||
14 | struct 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 | */ | ||
23 | struct BitMap * | ||
24 | bitmap_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 | */ | ||
32 | void | ||
33 | bitmap_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 | */ | ||
41 | void | ||
42 | bitmap_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 | */ | ||
52 | void | ||
53 | bitmap_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 | */ | ||
63 | int | ||
64 | bitmap_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 | */ | ||
73 | int | ||
74 | bitmap_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 | |||
4 | int 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 | |||
10 | int 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 | |||
19 | static 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 | |||
48 | static 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 | |||
57 | static 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 | |||
75 | int 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 | */ | ||
35 | struct 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 | */ | ||
57 | struct 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 | */ | ||
94 | static struct ConnCtx ctx_local; | ||
95 | |||
96 | /** | ||
97 | * context for the connection to remote MSHD | ||
98 | */ | ||
99 | static struct ConnCtx ctx_remote; | ||
100 | |||
101 | /** | ||
102 | * file handle for the stdin | ||
103 | */ | ||
104 | static struct GNUNET_DISK_FileHandle *fh_stdin; | ||
105 | |||
106 | /** | ||
107 | * file handle for stdout | ||
108 | */ | ||
109 | static struct GNUNET_DISK_FileHandle *fh_stdout; | ||
110 | |||
111 | /** | ||
112 | * file handle for stdout | ||
113 | */ | ||
114 | static struct GNUNET_DISK_FileHandle *fh_stderr; | ||
115 | |||
116 | /** | ||
117 | * The command string (cmd + parameters) | ||
118 | */ | ||
119 | static char *cmdstr; | ||
120 | |||
121 | /** | ||
122 | * Program help text | ||
123 | */ | ||
124 | static 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 | */ | ||
131 | static 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 | */ | ||
136 | struct GNUNET_CLIENT_TestHandle *test; | ||
137 | |||
138 | /** | ||
139 | * length of the cmdstr | ||
140 | */ | ||
141 | static size_t cmdstr_len; | ||
142 | |||
143 | /** | ||
144 | * Task to forward stdin to MSHD | ||
145 | */ | ||
146 | static GNUNET_SCHEDULER_TaskIdentifier task_fwd_stdin; | ||
147 | |||
148 | /** | ||
149 | * Shutdown task to disconnect client connections | ||
150 | */ | ||
151 | static GNUNET_SCHEDULER_TaskIdentifier task_shutdown; | ||
152 | |||
153 | /** | ||
154 | * flag to indicate successful completion by setting it to GNUNET_OK | ||
155 | */ | ||
156 | static int result; | ||
157 | |||
158 | /** | ||
159 | * different states | ||
160 | */ | ||
161 | enum 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 | */ | ||
189 | static struct winsize ws; | ||
190 | |||
191 | /** | ||
192 | * Terminal settings | ||
193 | */ | ||
194 | static struct termios tio; | ||
195 | |||
196 | /** | ||
197 | * The ip address of the remote node | ||
198 | */ | ||
199 | static in_addr_t target; | ||
200 | |||
201 | /** | ||
202 | * The port number where the MSHD is listening on target host | ||
203 | */ | ||
204 | static uint16_t target_port; | ||
205 | |||
206 | /** | ||
207 | * Do not allocate pseudo-tty | ||
208 | */ | ||
209 | static int disable_pty; | ||
210 | |||
211 | /** | ||
212 | * Are we capable of allocating pseudo-tty | ||
213 | */ | ||
214 | static int can_pty; | ||
215 | |||
216 | /** | ||
217 | * Do we need to allocate a pseudo-tty | ||
218 | */ | ||
219 | static int need_pty; | ||
220 | |||
221 | /** | ||
222 | * Did we set our terminal to raw mode | ||
223 | */ | ||
224 | static int tty_rawed; | ||
225 | |||
226 | /** | ||
227 | * Destroys a connection context | ||
228 | * | ||
229 | * @param ctx connection context | ||
230 | */ | ||
231 | static void | ||
232 | destroy_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 | */ | ||
267 | static void | ||
268 | do_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 | */ | ||
303 | static size_t | ||
304 | conn_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 | */ | ||
361 | static void | ||
362 | queue_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 | */ | ||
392 | static void | ||
393 | dispatch (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 | */ | ||
402 | static void | ||
403 | fwd_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 | */ | ||
448 | static int | ||
449 | handle_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 | */ | ||
492 | static int | ||
493 | handle_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 | */ | ||
514 | void | ||
515 | enter_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 | */ | ||
546 | static struct MSH_MSG_PtyMode * | ||
547 | gen_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 | */ | ||
607 | static int | ||
608 | handle_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 | */ | ||
645 | static int | ||
646 | handle_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 | */ | ||
666 | static void | ||
667 | target_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 | */ | ||
704 | static int | ||
705 | handle_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 | */ | ||
737 | static void | ||
738 | dispatch (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 | */ | ||
793 | static void | ||
794 | status_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 | */ | ||
826 | static int | ||
827 | read_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 | */ | ||
851 | static void | ||
852 | run (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 | */ | ||
918 | int | ||
919 | main (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 | |||
20 | static unsigned int port; | ||
21 | |||
22 | static struct GNUNET_CONFIGURATION_Handle *cfg; | ||
23 | |||
24 | static struct GNUNET_NETWORK_Handle *lsock; | ||
25 | |||
26 | static struct GNUNET_CONNECTION_Handle *conn; | ||
27 | |||
28 | static struct GNUNET_MessageHeader *msg; | ||
29 | |||
30 | static struct GNUNET_CONNECTION_TransmitHandle *handle_tx; | ||
31 | |||
32 | static struct GNUNET_DISK_FileHandle *fh_stdin; | ||
33 | |||
34 | static struct termios saved_tio; | ||
35 | |||
36 | static int in_raw_mode; | ||
37 | |||
38 | static int in_receive; | ||
39 | |||
40 | #define BUF_SIZE 512 | ||
41 | static char in_buf[BUF_SIZE]; | ||
42 | |||
43 | static ssize_t size_in_buf; | ||
44 | |||
45 | static void | ||
46 | do_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 | */ | ||
77 | void | ||
78 | enter_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 | */ | ||
120 | static void | ||
121 | receive (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 | */ | ||
149 | static void | ||
150 | read_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 | */ | ||
161 | static size_t | ||
162 | tx_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 | */ | ||
182 | static void | ||
183 | read_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 | */ | ||
208 | static size_t | ||
209 | tx_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 | */ | ||
239 | static void | ||
240 | accept_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 | */ | ||
329 | static void | ||
330 | run (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 | |||
364 | int 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 | */ | ||
39 | struct 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 | */ | ||
96 | struct 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 | */ | ||
123 | enum 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 | */ | ||
154 | struct 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 | */ | ||
181 | AddressMap *addrmap; | ||
182 | |||
183 | /** | ||
184 | * Reverse mapping of the address map | ||
185 | */ | ||
186 | struct ReverseAddressMap *rmap; | ||
187 | |||
188 | /** | ||
189 | * Rank of this process | ||
190 | */ | ||
191 | int rank; | ||
192 | |||
193 | /** | ||
194 | * Given width of the round -- how many other mshd instances verify our IP | ||
195 | * addresses in a round | ||
196 | */ | ||
197 | unsigned 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 | */ | ||
203 | unsigned int current_round_width; | ||
204 | |||
205 | /** | ||
206 | * The number of total mshd processes | ||
207 | */ | ||
208 | int nproc; | ||
209 | |||
210 | |||
211 | /****************************/ | ||
212 | /* static variables */ | ||
213 | /****************************/ | ||
214 | |||
215 | /** | ||
216 | * DLL head for the child process contexts | ||
217 | */ | ||
218 | static struct ChildProc *chld_head; | ||
219 | |||
220 | /** | ||
221 | * DLL tail for the child process contexts | ||
222 | */ | ||
223 | static struct ChildProc *chld_tail; | ||
224 | |||
225 | /** | ||
226 | * DLL head for address verification contexts | ||
227 | */ | ||
228 | static struct VerifyAddressesCtx *vactx_head; | ||
229 | |||
230 | /** | ||
231 | * DLL tail for address verification contexts | ||
232 | */ | ||
233 | static struct VerifyAddressesCtx *vactx_tail; | ||
234 | |||
235 | /** | ||
236 | * Array of our IP addresses in network-byte format | ||
237 | */ | ||
238 | static in_addr_t *s_addrs; | ||
239 | |||
240 | /** | ||
241 | * network handle for the listen socket | ||
242 | */ | ||
243 | static struct GNUNET_NETWORK_Handle *listen_socket; | ||
244 | |||
245 | /** | ||
246 | * The process handle of the process started by instance running with rank 0 | ||
247 | */ | ||
248 | static struct GNUNET_OS_Process *proc; | ||
249 | |||
250 | /** | ||
251 | * Task for running a round | ||
252 | */ | ||
253 | static GNUNET_SCHEDULER_TaskIdentifier rtask; | ||
254 | |||
255 | /** | ||
256 | * Task for asynchronous accept on the socket | ||
257 | */ | ||
258 | static GNUNET_SCHEDULER_TaskIdentifier accept_task; | ||
259 | |||
260 | /** | ||
261 | * Task for finalising a round | ||
262 | */ | ||
263 | static GNUNET_SCHEDULER_TaskIdentifier finalise_task; | ||
264 | |||
265 | /** | ||
266 | * Bitmap for checking which MPI processes have verified our addresses in the | ||
267 | * current round | ||
268 | */ | ||
269 | static struct BitMap *bitmap; | ||
270 | |||
271 | /** | ||
272 | * Instances addresses learnt in the current round | ||
273 | */ | ||
274 | struct InstanceAddrInfo **riainfos; | ||
275 | |||
276 | /** | ||
277 | * head for read context DLL | ||
278 | */ | ||
279 | static struct ReadContext *rhead; | ||
280 | |||
281 | /** | ||
282 | * tail for read context DLL | ||
283 | */ | ||
284 | static struct ReadContext *rtail; | ||
285 | |||
286 | /** | ||
287 | * arguments representing the command to run and its arguments | ||
288 | */ | ||
289 | static char **run_args; | ||
290 | |||
291 | /** | ||
292 | * The path of the unix domain socket we use for communication with local MSH clients | ||
293 | */ | ||
294 | static char *unixpath; | ||
295 | |||
296 | /** | ||
297 | * The file where the addresses of available hosts are written to | ||
298 | */ | ||
299 | static char *hostsfile; | ||
300 | |||
301 | /** | ||
302 | * shutdown task | ||
303 | */ | ||
304 | GNUNET_SCHEDULER_TaskIdentifier shutdown_task; | ||
305 | |||
306 | /** | ||
307 | * Shutdown polling task | ||
308 | */ | ||
309 | GNUNET_SCHEDULER_TaskIdentifier poll_shutdown_task; | ||
310 | |||
311 | /** | ||
312 | * Random hashcode for authentication | ||
313 | */ | ||
314 | struct GNUNET_HashCode shash; | ||
315 | |||
316 | /** | ||
317 | * Number of IP addresses | ||
318 | */ | ||
319 | static unsigned int nips; | ||
320 | |||
321 | /** | ||
322 | * Current IP verification round | ||
323 | */ | ||
324 | static unsigned int current_round; | ||
325 | |||
326 | /** | ||
327 | * Total number of rounds required | ||
328 | */ | ||
329 | static unsigned int total_rounds; | ||
330 | |||
331 | /** | ||
332 | * The port number of our local socket | ||
333 | */ | ||
334 | uint16_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 | */ | ||
343 | struct 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 | */ | ||
351 | static char ** | ||
352 | copy_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 | */ | ||
371 | static void | ||
372 | free_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 | */ | ||
388 | static void | ||
389 | do_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 | */ | ||
482 | static 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 | */ | ||
517 | static void | ||
518 | conn_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 | */ | ||
545 | static 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 | */ | ||
553 | static pid_t | ||
554 | spawn_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 | */ | ||
594 | static void | ||
595 | worker_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 | */ | ||
610 | static void | ||
611 | accept_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 | */ | ||
680 | static void | ||
681 | poll_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 | */ | ||
710 | static void | ||
711 | send_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 | */ | ||
738 | static void | ||
739 | proc_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 | */ | ||
756 | static void | ||
757 | local_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 | */ | ||
775 | static void | ||
776 | daemon_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 | */ | ||
793 | static void | ||
794 | terminate_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 | */ | ||
806 | static void | ||
807 | local_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 | */ | ||
846 | static void | ||
847 | run_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 | */ | ||
853 | static void | ||
854 | schedule_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 | */ | ||
973 | static void | ||
974 | cleanup_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 | */ | ||
994 | static void | ||
995 | finalise_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 | */ | ||
1026 | static void | ||
1027 | conn_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 | */ | ||
1061 | static size_t | ||
1062 | conn_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 | |||
1106 | static unsigned int bmx; | ||
1107 | |||
1108 | static int | ||
1109 | address_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 | */ | ||
1153 | static int | ||
1154 | verify_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 | */ | ||
1173 | static struct InstanceAddrInfo * | ||
1174 | parse_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 | */ | ||
1207 | static struct InstanceAddrInfo ** | ||
1208 | receive_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 | */ | ||
1288 | static int | ||
1289 | send_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 | */ | ||
1361 | static int | ||
1362 | run_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 | */ | ||
1397 | static void | ||
1398 | run_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 | */ | ||
1414 | static void | ||
1415 | run (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 | */ | ||
1482 | int | ||
1483 | main (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 | */ | ||
16 | extern AddressMap *addrmap; | ||
17 | |||
18 | /** | ||
19 | * Reverse mapping of the address map | ||
20 | */ | ||
21 | extern struct ReverseAddressMap *rmap; | ||
22 | |||
23 | /** | ||
24 | * Our instance rank | ||
25 | */ | ||
26 | extern int rank; | ||
27 | |||
28 | /** | ||
29 | * round width | ||
30 | */ | ||
31 | extern unsigned int rwidth; | ||
32 | |||
33 | /** | ||
34 | * Number of instances of mshd | ||
35 | */ | ||
36 | extern unsigned int nproc; | ||
37 | |||
38 | /** | ||
39 | * Random hashcode for authentication | ||
40 | */ | ||
41 | extern 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 | */ | ||
34 | struct 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 | */ | ||
91 | struct 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 | */ | ||
118 | enum 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 | */ | ||
149 | AddressMap *addrmap; | ||
150 | |||
151 | /** | ||
152 | * Reverse mapping of the address map | ||
153 | */ | ||
154 | struct ReverseAddressMap *rmap; | ||
155 | |||
156 | /** | ||
157 | * Rank of this process | ||
158 | */ | ||
159 | int rank; | ||
160 | |||
161 | /** | ||
162 | * width of the round -- how many other mshd instances verify our IP addresses | ||
163 | * in a round | ||
164 | */ | ||
165 | unsigned int rwidth; | ||
166 | |||
167 | /** | ||
168 | * The number of total mshd processes | ||
169 | */ | ||
170 | int nproc; | ||
171 | |||
172 | |||
173 | /****************************/ | ||
174 | /* static variables */ | ||
175 | /****************************/ | ||
176 | |||
177 | /** | ||
178 | * DLL head for address verification contexts | ||
179 | */ | ||
180 | static struct VerifyAddressesCtx *vactx_head; | ||
181 | |||
182 | /** | ||
183 | * DLL tail for address verification contexts | ||
184 | */ | ||
185 | static struct VerifyAddressesCtx *vactx_tail; | ||
186 | |||
187 | /** | ||
188 | * Array of our IP addresses in network-byte format | ||
189 | */ | ||
190 | static in_addr_t *s_addrs; | ||
191 | |||
192 | /** | ||
193 | * network handle for the listen socket | ||
194 | */ | ||
195 | static struct GNUNET_NETWORK_Handle *listen_socket; | ||
196 | |||
197 | /** | ||
198 | * The process handle of the process started by instance running with rank 0 | ||
199 | */ | ||
200 | static struct GNUNET_OS_Process *proc; | ||
201 | |||
202 | /** | ||
203 | * Task for running a round | ||
204 | */ | ||
205 | static GNUNET_SCHEDULER_TaskIdentifier rtask; | ||
206 | |||
207 | /** | ||
208 | * Task for asynchronous accept on the socket | ||
209 | */ | ||
210 | static GNUNET_SCHEDULER_TaskIdentifier atask; | ||
211 | |||
212 | /** | ||
213 | * Task for finalising a round | ||
214 | */ | ||
215 | static GNUNET_SCHEDULER_TaskIdentifier finalise_task; | ||
216 | |||
217 | /** | ||
218 | * Task for waiting for a shutdown signal | ||
219 | */ | ||
220 | static GNUNET_SCHEDULER_TaskIdentifier sigread_task; | ||
221 | |||
222 | /** | ||
223 | * Bitmap for checking which MPI processes have verified our addresses in the | ||
224 | * current round | ||
225 | */ | ||
226 | static struct BitMap *bitmap; | ||
227 | |||
228 | /** | ||
229 | * Instances addresses learnt in the current round | ||
230 | */ | ||
231 | struct InstanceAddrInfo **riainfos; | ||
232 | |||
233 | /** | ||
234 | * head for read context DLL | ||
235 | */ | ||
236 | static struct ReadContext *rhead; | ||
237 | |||
238 | /** | ||
239 | * tail for read context DLL | ||
240 | */ | ||
241 | static struct ReadContext *rtail; | ||
242 | |||
243 | /** | ||
244 | * arguments representing the command to run and its arguments | ||
245 | */ | ||
246 | static char **run_args; | ||
247 | |||
248 | /** | ||
249 | * the process handle for the command to run | ||
250 | */ | ||
251 | static struct GNUNET_OS_Process *process; | ||
252 | |||
253 | /** | ||
254 | * The path of the unix domain socket we use for communication with local MSH clients | ||
255 | */ | ||
256 | static char *unixpath; | ||
257 | |||
258 | /** | ||
259 | * The file where the addresses of available hosts are written to | ||
260 | */ | ||
261 | static char *hostsfile; | ||
262 | |||
263 | /** | ||
264 | * shutdown task | ||
265 | */ | ||
266 | GNUNET_SCHEDULER_TaskIdentifier shutdown_task; | ||
267 | |||
268 | /** | ||
269 | * Shutdown polling task | ||
270 | */ | ||
271 | GNUNET_SCHEDULER_TaskIdentifier poll_shutdown_task; | ||
272 | |||
273 | /** | ||
274 | * Random hashcode for authentication | ||
275 | */ | ||
276 | struct GNUNET_HashCode shash; | ||
277 | |||
278 | /** | ||
279 | * Number of IP addresses | ||
280 | */ | ||
281 | static unsigned int nips; | ||
282 | |||
283 | /** | ||
284 | * Current IP verification round | ||
285 | */ | ||
286 | static unsigned int current_round; | ||
287 | |||
288 | /** | ||
289 | * Do we have to create a pty | ||
290 | */ | ||
291 | static int need_pty; | ||
292 | |||
293 | /** | ||
294 | * The port number of our local socket | ||
295 | */ | ||
296 | uint16_t listen_port; | ||
297 | |||
298 | |||
299 | /** | ||
300 | * Perform cleanup for shutdown | ||
301 | * | ||
302 | * @param cls NULL | ||
303 | * @param tc scheduler task context | ||
304 | */ | ||
305 | static void | ||
306 | do_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 | */ | ||
378 | static 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 | */ | ||
414 | static void | ||
415 | conn_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 | */ | ||
444 | static pid_t | ||
445 | spawn_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 | */ | ||
482 | static void | ||
483 | accept_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 | */ | ||
544 | static void | ||
545 | poll_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 | */ | ||
574 | static void | ||
575 | send_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 | */ | ||
602 | static void | ||
603 | proc_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 | */ | ||
619 | static void | ||
620 | run_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 | */ | ||
626 | static void | ||
627 | schedule_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 | */ | ||
698 | static void | ||
699 | cleanup_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 | */ | ||
717 | static void | ||
718 | finalise_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 | */ | ||
749 | static void | ||
750 | conn_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 | */ | ||
784 | static size_t | ||
785 | conn_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 | |||
829 | static unsigned int bmx; | ||
830 | |||
831 | static int | ||
832 | address_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 | */ | ||
876 | static int | ||
877 | verify_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 | */ | ||
898 | static struct InstanceAddrInfo * | ||
899 | parse_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 | */ | ||
932 | static struct InstanceAddrInfo ** | ||
933 | receive_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 | */ | ||
1022 | static int | ||
1023 | send_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 | */ | ||
1099 | static int | ||
1100 | run_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 | */ | ||
1130 | static void | ||
1131 | run_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 | */ | ||
1145 | static char ** | ||
1146 | copy_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 | */ | ||
1165 | static void | ||
1166 | free_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 | */ | ||
1184 | static void | ||
1185 | run (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 | */ | ||
1249 | int | ||
1250 | main (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 | */ | ||
16 | struct 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 | */ | ||
66 | struct 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 | */ | ||
165 | struct 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 | */ | ||
182 | struct 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 | */ | ||
200 | struct 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 | */ | ||
218 | struct 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 | |||
234 | struct 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 | |||
249 | struct 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 | |||
269 | struct 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 | |||
283 | struct 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 | |||
297 | struct 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 | |||
24 | struct 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 | */ | ||
40 | static GNUNET_SCHEDULER_TaskIdentifier child_death_task_id; | ||
41 | |||
42 | /** | ||
43 | * Pipe used to communicate shutdown via signal. | ||
44 | */ | ||
45 | static struct GNUNET_DISK_PipeHandle *sigpipe; | ||
46 | |||
47 | /** | ||
48 | * Signal context for SIGCHLD | ||
49 | */ | ||
50 | static struct GNUNET_SIGNAL_Context *shc_chld; | ||
51 | |||
52 | /** | ||
53 | * hashmap for storing process monitoring context | ||
54 | */ | ||
55 | static 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 | */ | ||
65 | static void | ||
66 | child_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 | */ | ||
138 | static void | ||
139 | sighandler_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 | */ | ||
158 | void | ||
159 | MSH_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 | */ | ||
190 | static int | ||
191 | cleanup_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 | */ | ||
207 | void | ||
208 | MSH_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 | */ | ||
240 | void | ||
241 | MSH_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 | */ | ||
265 | void | ||
266 | MSH_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 | */ | ||
283 | int | ||
284 | MSH_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 | */ | ||
307 | int | ||
308 | MSH_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 | */ | ||
17 | void | ||
18 | MSH_pmonitor_init (); | ||
19 | |||
20 | |||
21 | /** | ||
22 | * shutdown process monitoring subsystem | ||
23 | */ | ||
24 | void | ||
25 | MSH_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 | */ | ||
36 | typedef 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 | */ | ||
49 | void | ||
50 | MSH_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 | */ | ||
61 | int | ||
62 | MSH_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 | */ | ||
73 | void | ||
74 | MSH_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 | */ | ||
85 | int | ||
86 | MSH_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 | |||
4 | int 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 | */ | ||
27 | int | ||
28 | reduce_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 | */ | ||
17 | int | ||
18 | reduce_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 | |||
3 | echo "Running bash on" $(hostname) | ||
4 | #xterm | ||
5 | bash | ||
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 | */ | ||
33 | static struct GNUNET_SERVER_Handle *local_serv; | ||
34 | |||
35 | /** | ||
36 | * server handle for acceptiong requests from remote MSHD instances | ||
37 | */ | ||
38 | static struct GNUNET_SERVER_Handle *daemon_serv; | ||
39 | |||
40 | /** | ||
41 | * Notification queue for the local server | ||
42 | */ | ||
43 | static struct GNUNET_SERVER_NotificationContext *local_serv_nc; | ||
44 | |||
45 | /** | ||
46 | * Notification queue for the daemon server | ||
47 | */ | ||
48 | static struct GNUNET_SERVER_NotificationContext *daemon_serv_nc; | ||
49 | |||
50 | /** | ||
51 | * Our UID. We use this for access checks | ||
52 | */ | ||
53 | uid_t our_uid; | ||
54 | |||
55 | /** | ||
56 | * Our GID. We use this for access checks | ||
57 | */ | ||
58 | uid_t our_gid; | ||
59 | |||
60 | |||
61 | /** | ||
62 | * Context for connections requiring to execute commands | ||
63 | */ | ||
64 | struct 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 | */ | ||
163 | speed_t | ||
164 | baud_to_speed(int baud); | ||
165 | |||
166 | |||
167 | /** | ||
168 | * Destroys an execution context | ||
169 | * | ||
170 | * @param ctx execution context | ||
171 | */ | ||
172 | static void | ||
173 | destroy_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 | */ | ||
214 | static int | ||
215 | parse_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 | */ | ||
252 | static struct GNUNET_MessageHeader * | ||
253 | create_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 | */ | ||
277 | static void | ||
278 | handle_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 | */ | ||
325 | static void | ||
326 | auth_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 | */ | ||
343 | static void | ||
344 | handle_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 | */ | ||
377 | static int | ||
378 | check_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 | */ | ||
394 | static void | ||
395 | local_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 | */ | ||
411 | int | ||
412 | init_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 | */ | ||
456 | void | ||
457 | shutdown_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 | */ | ||
481 | static void | ||
482 | handle_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 | */ | ||
522 | static int | ||
523 | redirect_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 | */ | ||
554 | static void | ||
555 | read_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 | */ | ||
582 | static void | ||
583 | read_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 | */ | ||
607 | static int | ||
608 | parse_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 | */ | ||
694 | static void | ||
695 | proc_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 | */ | ||
717 | static int | ||
718 | proc_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 | */ | ||
877 | static void | ||
878 | handle_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 | */ | ||
948 | static void | ||
949 | handle_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 | */ | ||
988 | static void | ||
989 | write_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 | */ | ||
1041 | static void | ||
1042 | handle_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 | */ | ||
1094 | static void | ||
1095 | handle_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 | */ | ||
1144 | static void | ||
1145 | daemon_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 | */ | ||
1164 | int | ||
1165 | init_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 | */ | ||
1199 | static void | ||
1200 | timeout_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 | */ | ||
1214 | void | ||
1215 | daemon_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 | */ | ||
1233 | void | ||
1234 | shutdown_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 | */ | ||
16 | void | ||
17 | shutdown_local_server (); | ||
18 | |||
19 | |||
20 | /** | ||
21 | * Shutdown the daemon server | ||
22 | */ | ||
23 | void | ||
24 | shutdown_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 | */ | ||
32 | void | ||
33 | daemon_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 | */ | ||
41 | int | ||
42 | init_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 | */ | ||
52 | int | ||
53 | init_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 | |||
24 | static 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 | */ | ||
36 | static int | ||
37 | iterator_cb (void *cls, uint16_t port, in_addr_t ip) | ||
38 | { | ||
39 | cnt++; | ||
40 | return GNUNET_OK; | ||
41 | } | ||
42 | |||
43 | |||
44 | static void | ||
45 | test_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 | |||
60 | static int | ||
61 | instance_address_info_free_iterator (void *cls, struct InstanceAddrInfo *iainfo) | ||
62 | { | ||
63 | instance_address_info_destroy (iainfo); | ||
64 | return GNUNET_OK; | ||
65 | } | ||
66 | |||
67 | |||
68 | static void | ||
69 | test_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 | |||
118 | int | ||
119 | main () | ||
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) \ | ||
22 | do { if (!cond){fprintf (stderr, "Assertion failed at %s:%d\n", __FILE__, __LINE__); ret;} }while(0) | ||
23 | |||
24 | int 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 | |||
11 | hostname | ||
12 | uptime | ||
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 | */ | ||
27 | static struct GNUNET_SIGNAL_Context *shc_chld; | ||
28 | |||
29 | /** | ||
30 | * Task to kill the child | ||
31 | */ | ||
32 | static GNUNET_SCHEDULER_TaskIdentifier child_death_task; | ||
33 | |||
34 | /** | ||
35 | * Task to read output from child | ||
36 | */ | ||
37 | static GNUNET_SCHEDULER_TaskIdentifier read_child_task; | ||
38 | |||
39 | /** | ||
40 | * Pipe used to communicate shutdown via signal. | ||
41 | */ | ||
42 | static struct GNUNET_DISK_PipeHandle *sigpipe; | ||
43 | |||
44 | static struct GNUNET_DISK_FileHandle *chld_io; | ||
45 | |||
46 | static struct GNUNET_CONNECTION_Handle *conn; | ||
47 | |||
48 | static struct GNUNET_CONNECTION_TransmitHandle *tx; | ||
49 | |||
50 | static char **chld_argv; | ||
51 | |||
52 | static char *cp; | ||
53 | static struct termios tio; | ||
54 | static struct winsize ws; | ||
55 | |||
56 | static int in_receive; | ||
57 | |||
58 | static char buf[BUF_SIZE]; | ||
59 | static size_t buf_off; | ||
60 | |||
61 | /** | ||
62 | * The process id of the child | ||
63 | */ | ||
64 | static 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 | */ | ||
72 | static char ** | ||
73 | copy_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 | */ | ||
92 | static void | ||
93 | free_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 | */ | ||
106 | static void | ||
107 | do_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 | */ | ||
144 | static void | ||
145 | read_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 | */ | ||
159 | static size_t | ||
160 | do_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 | */ | ||
184 | static void | ||
185 | read_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 | */ | ||
223 | static void | ||
224 | child_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 | */ | ||
250 | static void | ||
251 | sighandler_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 | */ | ||
267 | static int | ||
268 | parse_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 | */ | ||
344 | static int | ||
345 | spawn_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 | */ | ||
462 | static void | ||
463 | net_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 | */ | ||
564 | static void | ||
565 | run (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 | |||
640 | int 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 | */ | ||
64 | int | ||
65 | speed_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 | */ | ||
153 | speed_t | ||
154 | baud_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 | */ | ||
242 | static u_int | ||
243 | special_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 | */ | ||
255 | static cc_t | ||
256 | special_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 | */ | ||
272 | void | ||
273 | tty_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 | |||
326 | end: | ||
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 | */ | ||
340 | void | ||
341 | tty_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 | |||
469 | set: | ||
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 */ | ||
70 | TTYCHAR(VINTR, 1) | ||
71 | TTYCHAR(VQUIT, 2) | ||
72 | TTYCHAR(VERASE, 3) | ||
73 | #if defined(VKILL) | ||
74 | TTYCHAR(VKILL, 4) | ||
75 | #endif /* VKILL */ | ||
76 | TTYCHAR(VEOF, 5) | ||
77 | #if defined(VEOL) | ||
78 | TTYCHAR(VEOL, 6) | ||
79 | #endif /* VEOL */ | ||
80 | #ifdef VEOL2 | ||
81 | TTYCHAR(VEOL2, 7) | ||
82 | #endif /* VEOL2 */ | ||
83 | TTYCHAR(VSTART, 8) | ||
84 | TTYCHAR(VSTOP, 9) | ||
85 | #if defined(VSUSP) | ||
86 | TTYCHAR(VSUSP, 10) | ||
87 | #endif /* VSUSP */ | ||
88 | #if defined(VDSUSP) | ||
89 | TTYCHAR(VDSUSP, 11) | ||
90 | #endif /* VDSUSP */ | ||
91 | #if defined(VREPRINT) | ||
92 | TTYCHAR(VREPRINT, 12) | ||
93 | #endif /* VREPRINT */ | ||
94 | #if defined(VWERASE) | ||
95 | TTYCHAR(VWERASE, 13) | ||
96 | #endif /* VWERASE */ | ||
97 | #if defined(VLNEXT) | ||
98 | TTYCHAR(VLNEXT, 14) | ||
99 | #endif /* VLNEXT */ | ||
100 | #if defined(VFLUSH) | ||
101 | TTYCHAR(VFLUSH, 15) | ||
102 | #endif /* VFLUSH */ | ||
103 | #ifdef VSWTCH | ||
104 | TTYCHAR(VSWTCH, 16) | ||
105 | #endif /* VSWTCH */ | ||
106 | #if defined(VSTATUS) | ||
107 | TTYCHAR(VSTATUS, 17) | ||
108 | #endif /* VSTATUS */ | ||
109 | #ifdef VDISCARD | ||
110 | TTYCHAR(VDISCARD, 18) | ||
111 | #endif /* VDISCARD */ | ||
112 | |||
113 | /* name, field, op */ | ||
114 | TTYMODE(IGNPAR, c_iflag, 30) | ||
115 | TTYMODE(PARMRK, c_iflag, 31) | ||
116 | TTYMODE(INPCK, c_iflag, 32) | ||
117 | TTYMODE(ISTRIP, c_iflag, 33) | ||
118 | TTYMODE(INLCR, c_iflag, 34) | ||
119 | TTYMODE(IGNCR, c_iflag, 35) | ||
120 | TTYMODE(ICRNL, c_iflag, 36) | ||
121 | #if defined(IUCLC) | ||
122 | TTYMODE(IUCLC, c_iflag, 37) | ||
123 | #endif | ||
124 | TTYMODE(IXON, c_iflag, 38) | ||
125 | TTYMODE(IXANY, c_iflag, 39) | ||
126 | TTYMODE(IXOFF, c_iflag, 40) | ||
127 | #ifdef IMAXBEL | ||
128 | TTYMODE(IMAXBEL,c_iflag, 41) | ||
129 | #endif /* IMAXBEL */ | ||
130 | |||
131 | TTYMODE(ISIG, c_lflag, 50) | ||
132 | TTYMODE(ICANON, c_lflag, 51) | ||
133 | #ifdef XCASE | ||
134 | TTYMODE(XCASE, c_lflag, 52) | ||
135 | #endif | ||
136 | TTYMODE(ECHO, c_lflag, 53) | ||
137 | TTYMODE(ECHOE, c_lflag, 54) | ||
138 | TTYMODE(ECHOK, c_lflag, 55) | ||
139 | TTYMODE(ECHONL, c_lflag, 56) | ||
140 | TTYMODE(NOFLSH, c_lflag, 57) | ||
141 | TTYMODE(TOSTOP, c_lflag, 58) | ||
142 | #ifdef IEXTEN | ||
143 | TTYMODE(IEXTEN, c_lflag, 59) | ||
144 | #endif /* IEXTEN */ | ||
145 | #if defined(ECHOCTL) | ||
146 | TTYMODE(ECHOCTL,c_lflag, 60) | ||
147 | #endif /* ECHOCTL */ | ||
148 | #ifdef ECHOKE | ||
149 | TTYMODE(ECHOKE, c_lflag, 61) | ||
150 | #endif /* ECHOKE */ | ||
151 | #if defined(PENDIN) | ||
152 | TTYMODE(PENDIN, c_lflag, 62) | ||
153 | #endif /* PENDIN */ | ||
154 | |||
155 | TTYMODE(OPOST, c_oflag, 70) | ||
156 | #if defined(OLCUC) | ||
157 | TTYMODE(OLCUC, c_oflag, 71) | ||
158 | #endif | ||
159 | #ifdef ONLCR | ||
160 | TTYMODE(ONLCR, c_oflag, 72) | ||
161 | #endif | ||
162 | #ifdef OCRNL | ||
163 | TTYMODE(OCRNL, c_oflag, 73) | ||
164 | #endif | ||
165 | #ifdef ONOCR | ||
166 | TTYMODE(ONOCR, c_oflag, 74) | ||
167 | #endif | ||
168 | #ifdef ONLRET | ||
169 | TTYMODE(ONLRET, c_oflag, 75) | ||
170 | #endif | ||
171 | |||
172 | TTYMODE(CS7, c_cflag, 90) | ||
173 | TTYMODE(CS8, c_cflag, 91) | ||
174 | TTYMODE(PARENB, c_cflag, 92) | ||
175 | TTYMODE(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 | */ | ||
20 | struct GNUNET_NETWORK_Handle * | ||
21 | open_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 | */ | ||
69 | const char * | ||
70 | saddr2str (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 | */ | ||
90 | const char * | ||
91 | ip2str (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 | */ | ||
17 | struct GNUNET_NETWORK_Handle * | ||
18 | open_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 | */ | ||
28 | const char * | ||
29 | saddr2str (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 | */ | ||
38 | const char * | ||
39 | ip2str (const in_addr_t ip); | ||
40 | |||
41 | |||
42 | #endif /* #ifndef MSH_UTIL_H */ | ||
43 | /* end of MSH_UTIL_H */ | ||