summaryrefslogtreecommitdiffstats
path: root/stap-serverd
blob: 6970217d053620836b68ae85aac029a4e01e8e2d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
#!/bin/bash

# Compile server manager for systemtap
#
# Copyright (C) 2008 Red Hat Inc.
#
# This file is part of systemtap, and is free software.  You can
# redistribute it and/or modify it under the terms of the GNU General
# Public License (GPL); either version 2, or (at your option) any
# later version.

# This script publishes its presence on the network and then listens for
# incoming connections. When a connection is detected, the stap-server script
# is run to handle the request.

# Catch ctrl-c and other termination signals
trap 'terminate' SIGTERM SIGINT

#-----------------------------------------------------------------------------
# Helper functions.
#-----------------------------------------------------------------------------
# function: initialization PORT
function initialization {
    # Default settings.
    tmpdir_prefix_serverd=stap.serverd
    avahi_type=_stap._tcp
    port=$1
    test "X$port" = "X" && port=65000
    port2=$(($port + 1))
    if netstat -atn | awk '{print $4}' | cut -f2 -d: | egrep -q "^($port|$port2)\$"; then
        # Whoops, the port is busy; try another one.
        initialization $((1024+($port + $RANDOM)%64000))
    fi
}

# function: advertise_presence
#
# Advertise the availability of the server on the network.
function advertise_presence {
    # Build up a string representing our server's properties.
    # TODO: this needs fleshing out.
    local sysinfo=`uname -rvm`
    local txt="sysinfo=$sysinfo"

    # Call avahi-publish-service to advertise our presence.
    avahi-publish-service "Systemtap Compile Server on `uname -n`" \
	$avahi_type $port "$txt" > /dev/null 2>&1 &

    echo "Systemtap Compile Server on `uname -n` listening on port $port"
}

# function: listen
#
# Listen for and handle requests to the server.
function listen {
    # Work in a temporary directory
    tmpdir=`mktemp -dt $tmpdir_prefix_serverd.XXXXXX` || \
	fatal "ERROR: cannot create temporary directory " $tmpdir
    cd $tmpdir

    # Create a fifo for communicating with the server
    local fifo_name=$tmpdir_prefix_serverd.fifo
    mknod $fifo_name p || \
	fatal "ERROR: cannot create temporary fifo " $tmpdir/$fifo_name

    # Loop forever accepting requests
    first=1
    set -o pipefail # We want the status of 'nc' not 'stap-server'.
    while true
    do
	# Run this in the background and wait for it. This way any signals
	# received (i.e. SIGTERM) will be processed. Make sure we don't
	# advertise our presence until we're actually listening.
	for ((attempt=0; $attempt < 5; ++attempt))
	do
	    nc -l $port < $fifo_name | stap-server $((port + 1)) > $fifo_name 2>&1 &
	    if test $first = 1; then
		advertise_presence
		first=0
	    fi
	    wait '%nc' >/dev/null 2>&1
	    rc=$?
            if test $rc = 127 -o $rc = 0; then
		break; # success
            fi
	    sleep 1
	done
	if test $attempt = 5; then
	    fatal "ERROR: cannot listen on port $port. rc==$rc"
	fi
    done
    set +o pipefail # restore
}

# function: fatal [ MESSAGE ]
#
# Fatal error
# Prints its arguments to stderr and exits
function fatal {
    echo "$@" >&2
    terminate
    exit 1
}

# function: terminate
#
# Terminate gracefully.
function terminate {
    echo "$0: Exiting"

    # Kill the running 'avahi-publish-service' job
    kill -s SIGTERM %avahi-publish-service 2> /dev/null
    wait '%avahi-publish-service' >/dev/null 2>&1

    # Kill any running 'nc -l' job.
    kill -s SIGTERM "%nc -l" 2> /dev/null
    wait "%nc - l"  >/dev/null 2>&1

    # Clean up
    cd `dirname $tmpdir`
    rm -fr $tmpdir

    exit
}

#-----------------------------------------------------------------------------
# Beginning of main line execution.
#-----------------------------------------------------------------------------
initialization "$@"
listen