Reputation: 26713
I am trying to write a simple bash script that is listening on a port and responding with a trivial HTTP response. My specific issue is that I am not sure if the port is available and in case of bind failure I fall back to next port until bind succeeds.
So far to me the easiest way to achieve this was something like:
for (( i=$PORT_BASE; i < $(($PORT_BASE+$PORT_RANGE)); i++ ))
do
if [ $DEBUG -eq 1 ] ; then
echo trying to bind on $i
fi
/usr/bin/faucet $i --out --daemon echo test 2>/dev/null
if [ $? -eq 0 ] ; then #success?
port=$i
if [ $DEBUG -eq 1 ] ; then
echo "bound on port $port"
fi
break
fi
done
Here I am using faucet
from netpipes Ubuntu package.
The problem with this is that if I simply print "test" to the output, curl
complains about non-standard HTTP response (error code 18). That's fair enough as I don't print HTTP-compatible response.
If I replace echo test
with echo -ne "HTTP/1.0 200 OK\r\n\r\ntest"
, curl still complains:
user@server:$ faucet 10020 --out --daemon echo -ne "HTTP/1.0 200 OK\r\n\r\ntest"
...
user@client:$ curl ip.of.the.server:10020
curl: (56) Failure when receiving data from the peer
I think the problem lies in how faucet
is printing the response and handling the connection. For example if I do the server side in netcat
, curl works fine:
user@server:$ echo -ne "HTTP/1.0 200 OK\r\n\r\ntest\r\n" | nc -l 10020
...
user@client:$ curl ip.of.the.server:10020
test
user@client:$
I would be more than happy to replace faucet
with netcat
in my main script, but the problem is that I want to spawn independent server process to be able to run client from the same base shell. faucet
has a very handy --daemon
parameter as it forks to background and I can use $?
(exit status code) to check if bind succeeded. If I was to use netcat
for a similar purpose, I would have to fork it using &
and $?
would not work.
Does anybody know why faucet
isn't responding correctly in this particular case and/or can suggest a solution to this problem. I am not married neither to faucet
nor netcat
but would like the solution to be implemented using bash or it's utilities (as opposed to write something in yet another scripting language, such as Perl or Python).
Upvotes: 3
Views: 4236
Reputation: 21
Maybe have a look at the "sock" program of Richard Stevens as well. It has:
-F fork after connection accepted (TCP concurrent server)
http://www.icir.org/christian/sock.html
And using Bash you may also use:
echo $'HTTP/1.0 200 OK\r\n\r\ntest\r\n'
Upvotes: 2
Reputation: 204778
faucet 10020 --out --daemon \
echo -ne "HTTP/1.0 200 OK\r\nContent-Length: 4\r\n\r\ntest"
works fine. The issue seems to be that echo
doesn't know how to properly shutdown
a socket, using just close
instead, and curl
is unhappy about getting a -1 (disorderly shutdown) rather than a 0 (orderly shutdown) from recvfrom
.
Try socat
which sticks around to clean up after the child is done.
socat tcp-l:10020,fork,reuseaddr \
exec:'echo -ne "HTTP/1.0 200 OK\r\n\r\ntest"'
Upvotes: 5
Reputation: 11
How about using the program called tcpserver from the DJB ucspi-tcp package.
http://lserinol.blogspot.com/2008/12/simple-tcp-server-with-djb-tcpserver.html
An advanced alternative to netcat or nc respectively is ncat (part of nmap).
Upvotes: 1
Reputation: 19247
do you really need to use HTTP protocol, or is that just to please curl? if it's the latter, simply combine
faucet $port --out --daemon echo test
with
hose $server $port --in cat
Upvotes: 1