How to prevent python socket messages from overlaping in console? - python

I have a Python chat system which uses 1 thread for the user input and another thread for message receiving and printing. The issue is: if I receive a message at the same time that I'm taking user input, the text from the message ends up on the input line instead of its own separate line. How would I go about handling this?
A short version of my code:
def receive(cl,buffer):
msg = str(cl.recv(1024).decode())
print(msg)
_thread.start_new_thread(receive,(client,1024,))
while True:
msg = input("message:")
send(message)
For example: if I receive "hello world" from the server while I'm writing "hello server" in the console, it would look like this
"hello worldmessage:hello server"

Ideally, use two different windows for input and output. Consider existing chat apps where there is a window to type your message separate from the window that displays both your messages and the other users' messages. Otherwise, you can be typing as another message comes in.
Alternatively, use a threading.Lock() to serialize output. Only the thread holding the lock can output. Unfortunately, if you have:
with lock:
msg = input('message: ')
No other thread can print anything until you finish typing your message. Yet another reason to use separate windows for input and output.

I've decided to make a GUI for the system so I can display incoming messages in a widget and handle input from another widget.

Related

Using pwntools to interact with executable just halts on receive

I have a c exectuable that I want to exploit.
The output of that file looks like this:
$ ./vuln_nostack
Enter some text:
enteringTEXT
You entered: enteringTEXT
You enter some text, and the program spits it back.
I want to run this prorgam (and later exploit it) with python and pwntools.
So far, the functioning part of my pwntools program looks like this:
from concurrent.futures import process
from sys import stdout
from pwn import *
import time
pty = process.PTY
p = process("./vuln_nostack", stdin=pty, stdout=pty)
ss = p.recv()
p.clean()
asstring = ss.decode("utf-8")
print(asstring)
This works fine, it gets the first line and then prints it.
What I want to do now is to send a message to the program and then get the final line.
I have tried something along these lines:
p.send(b"dong")
p.clean()
print(p.recv())
I'm not sure whether or not the send actually ever sends anything, but as soon as I add the recv function, the prorgam just hangs and never finishes.
My guess is that the input to the executable is never given properly, and therefore it's still just waiting.
How do I actually get a message delivered to the exectuable so that it can move on and srever me the last line?
You can also use p.sendline():
p.sendline("payload")
This automatically adds a breakline after your bytes.
Moreover, to know whether your exploit is sending/receiving messages to/from the program, you can use debug context by adding this assignment:
context.log_level = 'debug'
The answer was a lot more simple than formerly presumed.
I just needed a breakline in the send:
p.send("payload \n")

Prompting with previous input from sys.stdin

I have a standard server-client TCP setup. The basic idea is a chat system. Looking at only the client's side of the conversation, the client prompts the user for input with:
sys.stdout.write('<%s> ' % username)
sys.stdout.flush()
using the following logic:
while True:
socket_list = [sys.stdin, s]
read_sockets, write_sockets, error_sockets = select.select(socket_list, [], [])
for sock in read_sockets:
if sock == s:
data = sock.recv(4096)
if data:
output('\a\r%s' % data) #output incoming message
sys.stdout.write('<%s> ' % username) #prompt for input
sys.stdout.flush()
else:
raise SystemExit
else:
msg = getASCII(sys.stdin.readline()) # returns only the ascii
if msg:
s.send(msg)
sys.stdout.write('<%s> ' % username)
sys.stdout.flush())
(Note: truncated snippet. Full code can be found here Linked code has been updated and so is no longer relevant.)
The problem is, when the user is typing and it gets an incoming message from the server, the client outputs the message and prompts for input again. The message that was being typed is still in the stdin buffer but has gone from the screen. If the user presses enter to send the message, the entire message will be sent including what was in the buffer, but on the user's screen, only the second part of the message, the part after the interruption, will be displayed.
I have a possible solution, which is that when I prompt for input, I check if there's anything in the buffer and output that along with the prompt, but I have no idea how to implement it. Any help is appreciated.
To implement your solution, you will have to read from stdin in an unbuffered way. readline() and read() block until an EOL or EOF. You need the data from stdin BEFORE the return key is pressed. To achieve that, this might prove helpful: http://code.activestate.com/recipes/134892-getch-like-unbuffered-character-reading-from-stdin/ When you are about to write data, you could then read from stdin, store it somewhere and output it again after outputting the message. As select won't be called for stdin, make a separate read-thread that reads stdin. Use locks for accessing stdin's data so far.
As an alternative to implementing your own editing line input function as discussed in the question's comments, consider this approach: Change the scrolling region to leave out the screen's bottom line (the user input line) and enter the scrolling region only temporarily to output incoming server messages. That answer contains an example.
The problem seems to be that you are letting the messages from the other user interrupt the typing. I recommend you either only listen to one thing at a time (when the user is typing you let him finish and press enter before listening for remote messages) or you listen for the user's input one key at a time and build up your own buffer (see Polling the keyboard (detect a keypress) in python). The downside to the later approach is that you need to implement key editing, etc. There may be a library that accomplishes this for you.
Note that in most chat programs, the area you type is in a separate window/screen region than where you are seeing the messages. All messages (yours as well as others) show up when complete in this message area. Perhaps you can use just display messages (independent of input) somewhere else on the screen.

Python client side in chat

I have a problem while trying to build the client side of a chat. I just in the begining, this is my code:
import socket
my_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
my_socket.connect(("10.10.10.69",1234))
while True:
message=raw_input("your message: ")
if(message=="quit"):
my_socket.close()
break
my_socket.send(message)
data=my_socket.recv(1024)
print "message from server:" , data
The problem is the raw_input. When a user sends a message the other users are stacked on the raw_input so only when they sends a message too they get the new messages.
How can I fix it (without using threads)?
As I commented, use select.select if your chat client is running in Unix.
For example:
import socket
import sys
import select
my_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
my_socket.connect(("10.10.10.69",1234))
sys.stdout.write('your message: ')
sys.stdout.flush()
while True:
r, w, x = select.select([sys.stdin, my_socket], [], [])
if not r:
continue
if r[0] is sys.stdin:
message = raw_input()
if message == "quit":
my_socket.close()
break
my_socket.send(message)
sys.stdout.write('your message: ')
sys.stdout.flush()
else:
data = my_socket.recv(1024)
print "message from server:" , data
raw_input holds up the thread it's in, so you can't retrieve messages in the same thread while waiting for it. Thus, I recommend using 2 threads, one which receives new messages (say every ten seconds) and one which sends messages (using code similar to the existing code).
If you're not committed to raw_input and are really against threads, you might want to look into the select module.
There are suggestions to use select() for stdin, but seems they aren't fixing the main problem. With select, imagine the local user is entering a line, and in a middle of this process your program outputs another user message, and, the editing of local input will be screwed. Either you don't allow to show new messages during entering the current one (why?) or screen is messed up. If you do this in a terminal, you should go using curses or some more powerful tool; with curses you can at least split input and output into different screen areas. Of course, a graphics library (like wxWidgets) is even more generally suitable for a user interface, if it's allowed in your case.

Optional input() statement

I'm creating an instant messenger program for my school's common drive. I have everything working except for on small detail. In the code below it checks for a new message from a friend and prints the last message they sent. If there are no messages it says so. The problem is when it moves to the next step of the code it waits for the user to put in an input. Until you give an input it won't let you receive any more messages because the program stops reading and searching the while loop and gets caught on the input statement. I want to know if there is anyway to make an input statement optional. To say that it doesn't require an input but if there is an input it will send it and do it's thing. I just can't seem to figure out a way to make the input statement optional. Any ideas or working code would be greatly appreciated. If you need the entire code I don't have a problem with sending it to you or posting it. This is the only bit of code that should really matter for this problem though.
LastMessage = ""
while Message:
Path = "Message"+SendTo+"-"+UserName+".txt"
if path.isfile(Path):
LoadMessage = open(Path, "rb")
NewMessage = pickle.load(LoadMessage)
LoadMessage.close()
else:
NewMessage = "Sorry, No messages found"
if LastMessage != NewMessage:
LastMessage = NewMessage
print(NewMessage)
print("")
SendMessage = raw_input() #--- This is where it gets caught up! ---
Save = open("Message"+UserName+"-"+SendTo+".txt", "wb")
pickle.dump(SendMessage, Save)
Save.close()
You have two main options as I see it:
Simultaneous input and checking (various options, search for e.g. threading or multiprocessing from the standard library); or
Input with timeout and loop (see e.g. How to set time limit on raw_input).
So it sounds like you want to do two separate things at the same time - look for input from a user and poll for new messages from other users. Jonrsharpe gives threading as his first option to solve this and I agree its the most straightforward. What you need to do is something like this:
import threading
class InputMessageThread(threading.Thread):
def run(self):
SendMessage = raw_input() # This thread will hang here for input but thats
# OK as original thread will keep going
Save = open("Message"+UserName+"-"+SendTo+".txt", "wb")
pickle.dump(SendMessage, Save)
Save.close()
inputthread = InputMessageThread()
inputthread.start()
# rest of your code here
While you are at it though you might want to look at some other issues. For example if I understand what you are trying to do correctly you are going to have a file containing a message from a source user to a destination user. But if the source user sends a second message before this file gets processed then the first message will be overwritten. In practice you may never see this but some sort of handshaking to make sure the message has actually been sent before you allow the next to be written would be a more robust approach.

How to avoid blocking using sockets (chat client)

I've been looking around all day, but I haven't been able to fix the problem I've got with my chat client here.
Here's the issue: I recently decided to change the client so that it would allow the user to input any message they wanted without having to wait for a reply first (blocking or something stops my program until a reply is in)
I decided to use the select.select module to do so, but after writing a couple different versions of my client today trying to get it to work, I keep getting stuck at this one point.
Whenever I enter a message, the loop gets stuck somewhere, (probably at .recv data)
how can I fix this? Nothing I try gets it to go by that.
Edit: To be more clear, when I run, I get to the point where I input the message, hit enter and then nothing happens at all. It just stays running like that.
from socket import *
import select
import sys #because why not?
print("New Chat Client Using Select Module")
HOST = input("Host: ")
PORT = int(input("Port: "))
s = socket(AF_INET,SOCK_STREAM)
print("Trying to connect....")
s.connect((HOST,PORT))
s.setblocking(0)
# Not including setblocking(0) because select handles that.
print("You just connected to",HOST,)
# Lets now try to handle the client a different way!
while True:
Incoming_data = [s]
Exportable_data = []
Exceptions = []
User_input = input("Your message: ")
rlist,wlist,xlist = select.select(Incoming_data,Exportable_data,Exceptions)
if User_input == True:
Exportable_data += [User_input]
for i in rlist:
data = i.recv(1024)
if data == "":
continue
for i in wlist:
if Exportable_data is True:
i.send(Exportable_data)
continue
Is there any way I can override the blocking (that I presume is the problem) when it's set to receive data? Won't s.setblocking(0) make it so it won't block(?) (With or without it still gets stuck)
Thanks for taking a look
I think you should have separate thread or process which will interact with your socket and another thread, which will accept user input and print chat messages. Interaction between the threads you can do using 2 queues: for incoming and outgoing messages.
Have a look at threading and queue modules.

Categories

Resources