2

I am trying to remotely change the cwd via socket lib on existing client, but I am running into the trouble every time I send the actual command "cd ..".

Server:

import socket, subprocess, os, sys

s = socket.socket()

host = socket.gethostname()
ip = socket.gethostbyname(host)
port = 8080

s.bind((ip,port))
s.listen(5)

c, a = s.accept()

fr = c.recv(10000)

cwd = fr

print("IP: "+str(a[0])+":"+str(a[1])+"\tCONNECTED")

while True:
    cmd = raw_input("\n"+cwd+"> ")
    if cmd != "":
        c.sendall(cmd)
        data = c.recv(1024)
        print("\n"+data)

    if cmd == "cd ..":
        c.sendall(cmd)
        cwd = c.recv(1024)

Client:

import socket, subprocess, os, sys



i = 1



cwd = os.getcwd()

while 1:
    s = socket.socket()
    host = socket.gethostname()
    ip = socket.gethostbyname(host)
    port = 8080

    try:
        s.settimeout(5)
        s.connect((ip,port))
        s.settimeout(None)
        s.sendall(cwd)

        i = 1

        while i == 1:
            cmd = s.recv(10000)
            if cmd != "over":
                sp = subprocess.Popen(cmd, shell=True, cwd=cwd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)
                out = sp.stdout.read()+"_________________________________"
                msg = out + sp.stderr.read()
                s.sendall(msg)
            if cmd == "over":
                s.close()
                i = 0

            if cmd == "cd ..":
                j = 0
                k = 0
                for i in cwd:
                    if i == '/':
                        k = j
                    j = j + 1
                cd = cwd[0:k]
                subprocess.Popen('echo', shell=True, cwd=cd)
                s.sendall(cd)

                print(cd)


    except socket.error:
        continue

Here is the error I get:

Traceback (most recent call last):
  File "PycharmProjects/server-client/test_hq.py", line 25, in <module>
    c.sendall(cmd)
  File "/usr/lib/python2.7/socket.py", line 228, in meth
    return getattr(self._sock,name)(*args)
socket.error: [Errno 104] Connection reset by peer

I can't figure it out what seems to be the problem...

Tyler Dee
  • 37
  • 9
  • I don't really see what you are trying to say – Tyler Dee Jul 11 '15 at 14:04
  • What does cmd have to do with this? – Tyler Dee Jul 11 '15 at 14:04
  • cmd here only points to the procedure I wrote – Tyler Dee Jul 11 '15 at 14:05
  • Aren't you trying to get the path after cd ? That loop makes absolutely no sense. Also are you sending and receiving from the server? – Padraic Cunningham Jul 11 '15 at 14:06
  • mhm, sorry. I skiped this part accidently. i checks for '/' in the current path (cwd) and when it hits the last '/' it saves the location and rewrite the current part from first char to the saved one (the ` cd = cwd[0:k] ` part) – Tyler Dee Jul 11 '15 at 14:08
  • I don't really see how this is helping my problem. For less confusion I will add the rest of the code, so it might help further comments. – Tyler Dee Jul 11 '15 at 14:14
  • Suggest you read the answer to this: http://stackoverflow.com/questions/1434451/what-does-connection-reset-by-peer-mean. The problem with trying to follow this is that you are ignoring socket errors in the client. I suggest that when you get one in your `except` block you (at least) print it out. – cdarke Jul 11 '15 at 14:49
  • Not related to your socket error, but using `subprocess` with `cd` will only change the current directory of the shell that you start with `subprocess` - it will not change the current directory of the client. For that you need `os.chdir()`. – cdarke Jul 11 '15 at 14:51
  • I tried your code, client and server, on the same machine, and it worked for me. Maybe you have a firewall or some other security restriction that is cutting the connection. – cdarke Jul 11 '15 at 15:00
  • @cdarke, not sure what you are running but the code does not work, it errors after a couple of cd .. and the `if cmd == "cd ..":` is never reached in the client. Catching an error and printing only outputs smething after the server has already crashed – Padraic Cunningham Jul 11 '15 at 15:09
  • @PadraicCunningham I didn't try a `cd`, just some ordinary commands like `ls`. I was more interested in the socket behaviour. – cdarke Jul 11 '15 at 15:10
  • @cdarke, the OP is asking about the cd .. command. There is no issue running ls, ls -l etc.. but enter cd .. twice and the code will crash – Padraic Cunningham Jul 11 '15 at 15:15
  • just like @PadraicCunningham said, I have no problems running those ordinary commands. The problem appears when I try to use cd .. – Tyler Dee Jul 11 '15 at 15:21
  • @TylerDee, I added full working code – Padraic Cunningham Jul 11 '15 at 16:40

2 Answers2

0

Considering the comment, this might help with your cd issues:

import re
import os.path

# Other stuff

        m = re.match(r'cd(?:\s+|$)(.*)', cmd)
        if m:
            dirs = m.groups()

            # Default to cd is home directory
            if len(dirs) == 0 or len(dirs[0]) == 0:
                dir = os.environ['HOME']
            else:
                dir = dirs[0]
                if dir == '..':
                    head, tail = os.path.split(cwd)
                    dir = head

            subprocess.Popen('echo', shell=True, cwd=dir)

            s.sendall(dir)

            # Update cwd
            cwd = dir

            print(dir)
        else:
            # Some other command
cdarke
  • 42,728
  • 8
  • 80
  • 84
  • `over` sends a sys.exit() command, basicly. Server closes the the connection with client. I need client to be on my disposal anytime I want to, so in that case I need it in the loop(even if it cant connect, or throws the socket error, I need it to keep trying). With `cd ..` I want to go to subdirectory of current shell, and I got stuck. – Tyler Dee Jul 11 '15 at 16:33
0

This should be closer to what you want, it is a lot simpler to receive and send once instead of repeatedly sending and receiving the same commands:

Client.py:

import socket, subprocess, os, sys

cwd = os.getcwd()

def make_socket():
    s = socket.socket()
    host = socket.gethostname()
    ip = socket.gethostbyname(host)
    port = 8080
    s.settimeout(5)
    s.connect((ip, port))
    s.settimeout(None)
    s.sendall(cwd)
    return s

while True:
    s = make_socket()
    try:
        while True:
            cmd = s.recv(10000)
            if cmd == "cd ..":
                # os.chdir("..") # uncomment to actually change directory
                cd = cwd.rsplit(os.sep(), 1)[0]
                subprocess.Popen('echo', shell=True, cwd=cd)
                s.sendall(cd)
            elif cmd != "over":
                sp = subprocess.Popen(cmd, shell=True, cwd=cwd, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
                                      stdin=subprocess.PIPE)
                out = sp.stdout.read() + "_________________________________"
                msg = out + sp.stderr.read()
                s.sendall(msg)
            else:
                print("closed")
                s.close()
                sys.exit(0)
    except socket.error as e:
        print(e)
        break

server.py:

import socket, subprocess, os, sys

s = socket.socket()

host = socket.gethostname()
ip = socket.gethostbyname(host)
port = 8080

s.bind((ip,port))
s.listen(5)

c, a = s.accept()

fr = c.recv(10000)

cwd = fr

print("IP: "+str(a[0])+":"+str(a[1])+"\tCONNECTED")

while True:
    cmd = raw_input("\n"+cwd+"> ")
    if cmd == "cd ..":
        print("sending 2")
        c.sendall(cmd)
        # os.chdir("..") # uncomment to change dir
        cwd = c.recv(10000)
    elif cmd != "":
        print("sending 1")
        c.sendall(cmd)
        data = c.recv(10000)
        print("\n"+data)

If you want to handle the client closing the socket and sys.exit(0) on the server side you should catch a socket.error on the server side to avoid a broken pipe error.

try:
    while True:
        print(os.getcwd(),44444)
        cmd = raw_input("\n"+cwd+"> ")
        if cmd != "" and cmd != "cd ..":
            print("sending 1")
            c.sendall(cmd)
            data = c.recv(10000)
            print("\n"+data)
        if cmd == "cd ..":
            print("sending 2")
            c.sendall(cmd)
            # os.chdir("..") # uncomment to change dir
            cwd = c.recv(10000)
except socket.error as e:
    print("Exception caught for {}".format(e.strerror))

If you want to do different things based on the errno you can compare in the except:

if e.errno == errno.EPIPE: i.e Broken pipe etc..

All the errno's are listed here in the errno docs

Padraic Cunningham
  • 176,452
  • 29
  • 245
  • 321