created autorun directory for commander-server files.
authorAdriana <adriana.draghici@cti.pub.ro>
Sat, 10 Apr 2010 08:24:29 +0000 (11:24 +0300)
committerAdriana <adriana.draghici@cti.pub.ro>
Sat, 10 Apr 2010 08:27:02 +0000 (11:27 +0300)
23 files changed:
autorun/PROTOCOL [new file with mode: 0644]
autorun/README [new file with mode: 0644]
autorun/Util.py [new file with mode: 0644]
autorun/commander/Client.py [new file with mode: 0644]
autorun/commander/ParserConf.py [new file with mode: 0644]
autorun/commander/SSHCommander.py [new file with mode: 0644]
autorun/commander/TrafficControl.py [new file with mode: 0644]
autorun/commander/XMLParser.py [new file with mode: 0644]
autorun/commander/run.sh [new file with mode: 0755]
autorun/server/AriaRun.py [new file with mode: 0644]
autorun/server/BitTorrentClientRun.py [new file with mode: 0644]
autorun/server/Client.py [new file with mode: 0644]
autorun/server/HrktorrentRun.py [new file with mode: 0644]
autorun/server/MainlineRun.py [new file with mode: 0644]
autorun/server/Server.py [new file with mode: 0644]
autorun/server/Server_NO_DAEMON.py [new file with mode: 0644]
autorun/server/TransmissionRun.py [new file with mode: 0644]
autorun/server/TriblerRun.py [new file with mode: 0644]
autorun/server/VuzeRun.py [new file with mode: 0644]
autorun/server/daemon.py [new file with mode: 0644]
autorun/xml/clients.xml [new file with mode: 0644]
autorun/xml/nodes.xml [new file with mode: 0644]
autorun/xml/swarm.xml [new file with mode: 0644]

diff --git a/autorun/PROTOCOL b/autorun/PROTOCOL
new file mode 100644 (file)
index 0000000..83f51fa
--- /dev/null
@@ -0,0 +1,64 @@
+
+Comunicare Client <-> Server
+
+
+++---------+  start server   +----------------------------------------------------------+
+|         |---------------> | +--------------+     +--------+    +-------------+       |    
+| Client  |  send commands  | | Server daemon|     | tribler|    | transmission|  .... |
+|         |---------------> | +--------------+     +--------+    +-------------+       |
+++---------+<--------------- +----------------------------------------------------------+
+               ack
+
+
+
+1. Pas initial - NU MAI ESTE NEVOIE
+  - informatiile legate de clienti
+  - msg 1: tipul mesajului: CONFIG_MSG (definit in Util.py)
+  - msg 2: dictionar de dictionare cu datele din clients.xml
+       exp: {"tribler":{FILE:"Tribler/Tools/cmdline.py",
+               RUN_TYPE:"script",
+               INTERPRETER:"python", PREFIX:"PYTHONPATH=.",SUFFIX:"",
+               UP_LIMIT_OPTION:"",DL_LIMIT_OPTION:"", PORT_OPTION:"-p",
+               LOG_DIR_OPTION:"-l",DL_DIR_OPTION:"-d"}
+            }  
+ - dupa fiecare msg 1,2 Serverul trimite un mesaj care indica daca a aparut sau nu vreo eroare 
+
+
+
+2. Mesaje START
+ - trimis pt pornirea unui client
+ - msg 1: tipul mesajului START_MSG (definit in Util.py)
+ - msg 2: dictionar cu parametrii
+       exp: {CLIENT:"tribler",
+               BASE_DIR: "/usr/bin", 
+               UP_LIMIT: "512", 
+               DL_LIMIT:"256", 
+               PORT:"9999", 
+               DL_DIR:"/this/dir", 
+               LOG_DIR:"/this/dir", 
+               OUT_FILE: "output_file",  ??? nu stim exact scopul lui
+               LOG_FILE:"log_file", 
+               TORRENT: "torrent file"
+               }
+
+
+ - dupa fiecare msg 1,2 Serverul trimite un mesaj care indica daca a aparut sau nu vreo eroare 
+       -> dupa msg 2 serverul trimite "<pid client torrent>" 
+
+3. Mesaje STOP
+ - trimis pt oprirea unui client
+ - msg 1: STOP_MSG (definit in Util.py)
+ - msg 2: numele clientului (un string)
+ - dupa fiecare msg 1,2 Serverul trimite un mesaj care indica daca a aparut sau nu vreo eroare 
+
+4. Mesaje STATUS
+ - trimise de client pt interogarea starii
+ - msg 1: tipul mesajului STATUS_MSG (definit in Util.py)
+ - msg 2: dictionar - TODO
+ - dupa fiecare msg 1,2 Serverul trimite un mesaj care indica daca a aparut sau nu vreo eroare 
+
+
+
+
+.....
diff --git a/autorun/README b/autorun/README
new file mode 100644 (file)
index 0000000..27db487
--- /dev/null
@@ -0,0 +1,13 @@
+server/Server.py - serverul ce ruleaza ca daemon
+server/Server_NO_DAEMON.py - folosit pt testarea functionarii, nu este daemon
+server/Client.py - testeaza comunicatia cu serverul folosind sockets
+                - usage: python Client.py torrent_file
+Util.py - constante folosite atat de server cat si de commander
+start-clients/BitTorrentClientRun - porneste instante de clienti bittorrent
+start-clients/*Run.py - subclase ale BitTorrentClientRun modificate pt fiecare client in parte.
+commander/ -clasele pt Commander 
+
+
+
+
+
diff --git a/autorun/Util.py b/autorun/Util.py
new file mode 100644 (file)
index 0000000..d5da785
--- /dev/null
@@ -0,0 +1,32 @@
+
+#!/usr/bin/env python
+
+SERVER_PORT = 10004 
+SERVER_HOST = "127.0.0.1"
+
+""" Message types: client -> server """
+
+START_MSG = "1";
+STOP_MSG = "2";
+STATUS_MSG = "3";
+
+ACK_MSG = "ACK" # send by server to the client after receiving a message if everything was ok
+ERROR_MSG = "ERROR " # send by server to the client if the parameters were incorrect 
+                       # or the client could not be started etc
+
+#xml tags from swarm.xml
+CLIENT = "client"
+BASE_DIR = "base"
+UP_LIMIT = "upload_limit"
+DL_LIMIT = "download_limit"
+DL_DIR = "download_dir"
+LOG_DIR = "logging_dir"
+OUT_FILE = "output_file"
+LOG_FILE = "log_file"
+PORT = "port"
+TORRENT = "torrent_file"
+
+#clients
+TRIBLER = "tribler"
+TRANSMISSION = "transmission"
+
diff --git a/autorun/commander/Client.py b/autorun/commander/Client.py
new file mode 100644 (file)
index 0000000..e2b6d64
--- /dev/null
@@ -0,0 +1,152 @@
+import sys, socket
+import pickle
+import paramiko
+import os
+from Util import *
+from XMLParser import *
+from TrafficControl import *
+from threading import Thread
+paramiko.util.log_to_file('/tmp/paramiko.log')
+
+MSGLEN = 1024
+DEBUG = True
+
+class Commander(Thread):
+       def __init__(self, nodes_xml, swarm_xml):
+               Thread.__init__(self)
+               self.nodes = Nodes(nodes_xml);
+               self.swarm = Swarm(swarm_xml);
+               self.tc = TrafficControl("openvz");
+               self.sshc = paramiko.SSHClient()
+               self.sshc.set_missing_host_key_policy(paramiko.AutoAddPolicy())
+               self.sshc.load_system_host_keys()
+               self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+               
+       def sendSSHComm(self, hostname, username, port, comm):
+               try:
+                       self.sshc.connect(hostname=hostname,  username=username, port=port)
+                       stdin, stdout, stderr = self.sshc.exec_command(comm)
+                       print stdout.readlines()
+               except Exception as e:
+                       print e
+               finally:
+                       self.sshc.close()
+       
+       def sendMultipleSSHComm(self, hostname, username, port, comms):
+               try:
+                       self.sshc.connect(hostname=hostname,  username=username, port=port)
+                       for c in comms:
+                               stdin, stdout, stderr = self.sshc.exec_command(comm)
+               except Exception as e:
+                       print e
+               finally: 
+                       self.sshc.close()
+       
+       def sendComm(self, hostname, port, msg_type, config_data):
+               try:
+                       self.sock.connect((hostname, port))
+                       self.send(msg_type)
+                       response = self.recv_msg()
+                       if response == ACK_MSG:
+                               self.sendMsg(pickle.dumps(config_data))
+                               response = self.recv_msg()
+                       print "->>>>>>>>>>>>>>>>>>>>>>>>>", response
+               except Exception as e:
+                       print e
+               finally:
+                       self.sock.close()
+
+       def sendMsg(self, msg):
+               totalsent = 0
+               while totalsent < len(msg):
+                       sent = self.sock.send(msg[totalsent:])
+                       if sent == 0:
+                               raise RuntimeError,     "socket connection broken"
+                       totalsent = totalsent + sent
+       
+       def recvMsg(self):
+               msg = ''
+               chunk = self.sock.recv(MSGLEN)
+               if chunk == '':
+                       raise RuntimeError,     "socket connection broken"
+               msg = msg + chunk
+               
+               return msg
+                       
+       def startDaemon(self, node):
+               print node.daemon_dir
+               comm = "PYTHONPATH=/home/p2p/cs-p2p-next/bt_comm:/home/p2p/cs-p2p-next/bt_comm/start-clients/ python /home/p2p/cs-p2p-next/bt_comm/server/Server.py start " + node.public_address + " " + node.listen_port
+               print comm
+               #self.printDummyCommand(node.public_address, node.public_port, node.ssh_port, comm)
+               self.sendSSHComm(node.public_address, node.username, int(node.ssh_port), comm)
+               self.sendSSHComm(node.public_address, node.username, int(node.ssh_port), "ps -ef | grep Server")
+       
+       def applyTC(self, node):
+               si = self.swarm.getSIByNode(node)
+               self.tc.config(node.public_address, node.public_port, node.public_iface, \
+                               node.private_address, node.private_port, node.private_iface)
+               self.tc.set_upload_limit(si.upload_limit)
+               self.tc.set_download_limit(si.download_limit)
+               
+               commands = self.tc.get_all_commands()
+               self.printDummyCommand(node.public_address, node.public_port, node.ssh_port, commands)
+               #sendMultipleSSHComm(node.public_address, node.username, node.ssh_port, commands)
+       
+       def sendSIStart(self, si):
+               node = self.nodes.getNodeBySi(si)
+               base_path = node.getClientBaseDir(si.btclient)
+               torrent_file = self.swarm.getTorrentFile()
+               
+               config_data = {CLIENT : si.btclient, 
+                                       BASE_DIR : base_path, 
+                                       UP_LIMIT : si.download_limit,
+                                       DL_LIMIT : si.upload_limit,
+                                       PORT : node.public_port,
+                                       DL_DIR : si.download_dir, 
+                                       LOG_DIR : si.log_dir, 
+                                       OUT_FILE : si.output_file,
+                                       LOG_FILE : si.log_file,
+                                       TORRENT : torrent_file
+                                       }
+               
+               self.printDummyCommand(node.public_address, node.listen_port, START_MSG, config_data)
+               self.sendComm(node.public_address, int(node.listen_port), START_MSG, config_data)
+       
+       def printDummyCommand(self, public_address, public_port, option1, data):
+               print "----------------------"
+               print "sending to: [%s:%s] with option %s" %(public_address, public_port, option1)
+               print "this data: %s" %(data)
+               print "----------------------\n"
+               
+       
+       def sendSIStop(self, node):
+               pass
+               
+       def sendSIStatus(self, node):
+               pass
+       
+       def startAll(self):
+               for node in self.nodes.getNodes():
+                       #self.applyTC(node)
+                       self.startDaemon(node)
+               
+               for si in self.swarm.getSIs():
+                       self.sendSIStart(si)
+                       
+       def run(self):
+               self.printUsage()
+               while True:
+                       k = raw_input("Choose option:")
+                       if k == '': break
+                       elif k == '1':
+                               self.startAll()
+       
+       def printUsage(self):
+               print "=========Commander Options=========="
+               print "1. Start Swarm"
+               print "===================================="
+
+if __name__ == "__main__":
+       c = Commander("../xml/nodes.xml", "../xml/swarm.xml")
+       c.start()
+
diff --git a/autorun/commander/ParserConf.py b/autorun/commander/ParserConf.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/autorun/commander/SSHCommander.py b/autorun/commander/SSHCommander.py
new file mode 100644 (file)
index 0000000..25bfcac
--- /dev/null
@@ -0,0 +1,50 @@
+import paramiko
+import os
+paramiko.util.log_to_file('/tmp/paramiko.log')
+
+class SSHCommander:
+       def __init__(self, hostname, username, port):
+               #self.sshclient = paramiko.Transport((hostname, port))
+               self.sshclient = paramiko.SSHClient()
+               self.sshclient.set_missing_host_key_policy(paramiko.AutoAddPolicy())
+               self.sshclient.load_system_host_keys()
+               #~ transport = paramiko.Transport((host, port))
+               #pkey_file = os.path.expanduser('~/.ssh/id_rsa')
+               #self.pkey = paramiko.RSAKey.from_private_key_file(pkey_file)
+               self.hostname = hostname
+               self.username = username
+               self.port = port
+       
+       def connect(self):
+               self.sshclient.connect(hostname=self.hostname, username=self.username, port=self.port)
+               #self.sshclient.connect(username=self.username, pkey=self.pkey)
+
+       def emitCommand(self, comm):
+               stdin, stdout, stderr = self.sshclient.exec_command(comm)
+               print stdout.readlines()
+       
+       def closeConnection(self):
+               self.sshclient.close()
+               
+
+sshc = SSHCommander("141.85.224.204", "p2p", 20322)
+sshc.connect()
+sshc.emitCommand("ls -lh")
+sshc.closeConnection()
+
+#~ #client.connect(hostname='p2p-next-07.grid.pub.ro',  username='p2p')
+#~ stdin, stdout, stderr = client.exec_command('touch gugu dudu')
+#~ stdin, stdout, stderr = client.exec_command('ls -l')
+#~ print stdout.readlines()
+#~ client.close()
+
+
+#~ host = "p2p-next-09.grid.pub.ro"
+#~ port = 22
+#~ transport = paramiko.Transport((host, port))
+
+#~ privatekeyfile = os.path.expanduser('~/.ssh/id_rsa')
+#~ mykey = paramiko.RSAKey.from_private_key_file(privatekeyfile)
+#~ username = 'p2p'
+#~ transport.connect(username = username, pkey = mykey)
+
diff --git a/autorun/commander/TrafficControl.py b/autorun/commander/TrafficControl.py
new file mode 100644 (file)
index 0000000..1abe51f
--- /dev/null
@@ -0,0 +1,108 @@
+#!/usr/bin/env python
+
+"""
+ Traffic control interface for Linux tc
+ 2010, Razvan Deaconescu, razvan.deaconescu@cs.pub.ro
+"""
+
+import sys
+import sqlite3
+import os.path
+
+DEBUG = False
+
+class TrafficControl:
+    """
+    Basic class interface to Linux tc
+    """
+    
+    def __init__(self, node_type):
+        self.node_type = node_type
+        self.upload_limit = -1
+        self.download_limit = -1
+
+    def config(self, host_address, host_port, host_iface,
+            vm_address = None, vm_port = -1, vm_iface = None):
+        self.host_address = host_address
+        self.host_port = host_port
+        self.host_iface = host_iface
+        self.vm_address = vm_address
+        self.vm_port = vm_port
+        self.vm_iface = vm_iface
+
+    """
+    Set upload limit. Argument in KB/s (kilobytes/s)
+    """
+    def set_upload_limit(self, upload_limit):
+        self.upload_limit = upload_limit
+
+    """
+    Set download limit. Argument in KB/s (kilobytes/s)
+    """
+    def set_download_limit(self, download_limit):
+        self.download_limit = download_limit
+
+    def get_upload_limit_commands(self):
+        upload_limit_commands = []
+        upload_limit_commands.append("tc qdisc add dev %s root handle 1: htb default 90" % (self.vm_iface))
+        upload_limit_commands.append("tc class add dev %s parent 1: classid 1:1 htb rate %skb ceil %skb" % (self.vm_iface, self.upload_limit, self.upload_limit))
+        upload_limit_commands.append("tc qdisc add dev %s parent 1:1 handle 10: sfq perturb 10" % (self.vm_iface))
+        upload_limit_commands.append("tc filter add dev %s parent 1:0 protocol ip u32 match ip dst %s match ip dport %s 0xffff classid 1:1" % (self.vm_iface, self.vm_address, self.vm_port))
+
+        return upload_limit_commands
+
+    def get_download_limit_commands(self):
+        download_limit_commands = []
+        download_limit_commands.append("tc qdisc add dev %s root handle 1: htb default 90" % (self.host_iface))
+        download_limit_commands.append("tc class add dev %s parent 1: classid 1:1 htb rate %skb ceil %skb" % (self.host_iface, self.download_limit, self.download_limit))
+        download_limit_commands.append("tc qdisc add dev %s parent 1:1 handle 10: sfq perturb 10" % (self.host_iface))
+        download_limit_commands.append("tc filter add dev %s parent 1:0 protocol ip u32 match ip src %s classid 1:1" % (self.host_iface, self.vm_address))
+
+        return download_limit_commands
+
+    def get_flush_commands(self):
+        flush_commands = []
+        flush_commands.append("tc qdisc del dev %s root handle 1:" % (self.host_iface))
+        flush_commands.append("tc qdisc del dev %s root handle 1:" % (self.vm_iface))
+
+        return flush_commands
+
+    def get_all_commands(self):
+        all_commands = []
+       all_commands.extend(self.get_upload_limit_commands())
+       all_commands.extend(self.get_download_limit_commands())
+       all_commands.extend(self.get_flush_commands())
+
+       return all_commands
+  
+
+def print_commands(commands, header):
+    print "\n\t== %s ==\n" % (header)
+    
+    for c in commands:
+        print c
+
+def main():
+
+    """
+    Test case
+    """
+
+    tc = TrafficControl("openvz")
+    tc.config("141.85.224.201", 10150, "eth0",
+            "172.16.10.0", 10150, "venet0")
+    tc.set_upload_limit(512)
+    tc.set_download_limit(256)
+
+    upload_limit_commands = tc.get_upload_limit_commands()
+    download_limit_commands = tc.get_download_limit_commands()
+    flush_commands = tc.get_flush_commands()
+    all_commands = tc.get_all_commands()
+
+    print_commands(upload_limit_commands, "upload limit commands")
+    print_commands(download_limit_commands, "download limit commands")
+    print_commands(flush_commands, "flush commands")
+    print_commands(all_commands, "all commands")
+
+if __name__ == "__main__":
+    sys.exit(main())
diff --git a/autorun/commander/XMLParser.py b/autorun/commander/XMLParser.py
new file mode 100644 (file)
index 0000000..25be3af
--- /dev/null
@@ -0,0 +1,110 @@
+from lxml import etree 
+
+class SwarmInstance:
+       def __init__(self, id, list):
+               self.id = id;
+               self.node_id = list[0];
+               self.btclient = list[1];
+               self.upload_limit = list[2];
+               self.download_limit = list[3];
+               self.download_dir = list[4];
+               self.log_dir = list[5];
+               self.log_file = list[6];
+               self.output_dir = list[7];
+               self.output_file = list[8];
+       
+       def __str__(self):
+               return '[%s: %s: %s: %s: %s: %s: %s: %s]' \
+                       %(self.id, self.node_id, self.btclient, self.upload_limit, \
+                               self.download_limit, self.download_dir, self.log_dir, self.output_dir);
+       
+class Node:
+       def __init__(self, id, list):
+               self.id = id;
+               self.public_address = list[0];
+               self.public_port = list[1];
+               self.public_iface = list[2];
+               self.private_address = list[3];
+               self.private_port = list[4];
+               self.private_iface = list[5];
+               self.ssh_port = list[6];
+               self.username = list[7];
+               self.listen_port = list[8];
+               self.clients_base_dir = list[10];
+               self.daemon_dir = list[9];
+       
+       def __str__(self):
+               return '[%s: %s: %s: %s: %s: %s %s: %s]' \
+                       %(self.id, self.public_address, self.public_port, self.private_address, \
+                               self.private_port, self.ssh_port,  self.username, self.clients_base_dir);
+       
+       def getClientBaseDir(self, client):
+               return self.clients_base_dir[client]
+
+class Nodes:
+       def __init__(self, nodes_xml):
+               try:
+                       tree = etree.parse(nodes_xml)
+                       root = tree.getroot()
+                       self.nodes = []
+                       for elem in root:
+                               id = elem.get("id")
+                               list = [elem2.text for elem2 in elem[:len(elem)-1]]
+                               client_paths = {}
+                               for elem2 in elem[len(elem)-1]:
+                                       client_id = elem2.get("id");
+                                       client_paths [client_id]=elem2[0].text;
+                               list.append(client_paths);
+                               self.nodes.append(Node(id, list))
+               except IOError as e:
+                       print e
+                       return None
+       
+       def getNode(self, id):
+               for node in self.nodes:
+                       if node.id == id:
+                               return node
+       
+       def getNodeBySi(self, si):
+               for node in self.nodes:
+                       if node.id == si.node_id:
+                               return node
+       
+       def getNodes(self):
+               return self.nodes
+       
+
+class Swarm:
+       def __init__(self, swarm_xml):
+               try:
+                       tree = etree.parse(swarm_xml)
+                       root = tree.getroot()
+                       self.swarm = []
+                       self.torrent_file = root[0].text
+                       for elem in root[1:]:
+                               id = elem.get("id")
+                               list = [elem2.text for elem2 in elem[:len(elem)-1]]
+                               self.swarm.append(SwarmInstance(id, list))
+               except IOError as e:
+                       print e
+                       return None
+                       
+       def  getSIByNode(self, node):
+               for si in self.swarm:
+                       if si.node_id == node.id:
+                               return si
+
+       def getTorrentFile(self):
+               return self.torrent_file
+       
+       def getSIs(self):
+               return self.swarm
+
+#~ swarm = Swarm("swarm.xml")
+#~ for si in swarm.getSIs():
+       #~ print si
+
+#~ nodes = Nodes("nodes.xml")
+#~ for node in nodes.getNodes():
+       #~ print node
+       #~ print node.getClientBaseDir('libtorrent')
diff --git a/autorun/commander/run.sh b/autorun/commander/run.sh
new file mode 100755 (executable)
index 0000000..9a41b17
--- /dev/null
@@ -0,0 +1,2 @@
+#!/bin/bash
+PYTHONPATH=/home/marius/cs-p2p-next/bt_comm/:/home/marius/cs-p2p-next/bt_comm/xml/ python Client.py
diff --git a/autorun/server/AriaRun.py b/autorun/server/AriaRun.py
new file mode 100644 (file)
index 0000000..f955872
--- /dev/null
@@ -0,0 +1,34 @@
+#!/usr/bin/env python
+
+"""
+ Base class for running Aria client instances
+ 2010, Razvan Deaconescu, razvan.deaconescu@cs.pub.ro
+"""
+
+import sys
+import os.path
+from BitTorrentClientRun import BitTorrentClientRun
+
+DEBUG = False
+
+
+class AriaRun(BitTorrentClientRun):
+    def __init__(self, base_path):
+        BitTorrentClientRun.__init__(self, base_path,
+                "$base_path/src/aria2c --log-level=debug --dir=$download_dir --log=$log_dir/$log_file --torrent-file=$torrent_file &> $output_dir/$output_file",
+                "$base_path/src/aria2c --log-level=debug --dir=$download_dir --log=$log_dir/$log_file --torrent-file=$torrent_file &> $output_dir/$output_file")
+
+
+def main():
+
+    """
+    Test case
+    """
+
+    ar = AriaRun("/home/p2p/p2p-clients/aria")
+    ar.config_run("/home/p2p/p2p-dld/aria", "/home/p2p/p2p-log/aria", "aria-fedora.out", "/home/p2p/p2p-log/aria", "aria-fedora.log", 10150, "/home/p2p/p2p-meta/fedora.torrent")
+    ar.start()
+
+
+if __name__ == "__main__":
+    sys.exit(main())
diff --git a/autorun/server/BitTorrentClientRun.py b/autorun/server/BitTorrentClientRun.py
new file mode 100644 (file)
index 0000000..935c19d
--- /dev/null
@@ -0,0 +1,101 @@
+#!/usr/bin/env python
+
+"""
+ Base class for running BitTorrent client instances
+ 2010, Razvan Deaconescu, razvan.deaconescu@cs.pub.ro
+"""
+
+import sys
+import os
+import os.path
+import subprocess
+import shlex
+from string import Template
+
+DEBUG = True
+
+class BitTorrentClientRun:
+    def __init__(self, base_path, simple_run_expr, logging_run_expr):
+        self.base_path = base_path
+        self.simple_run_expr = simple_run_expr
+        self.logging_run_expr = logging_run_expr
+
+    def config_run(self, download_dir, output_dir, output_file, log_dir, log_file, port, torrent_file):
+        self.download_dir = download_dir
+        self.output_dir = output_dir
+        self.output_file = output_file # output from stdout
+        self.log_dir = log_dir
+        self.log_file = log_file # output from stderr
+        self.port = port
+        self.torrent_file = torrent_file
+
+    def start(self):
+        t = Template(self.simple_run_expr)
+        self.simple_run_command = t.substitute(
+                base_path = self.base_path,
+                download_dir = self.download_dir,
+                output_dir = self.output_dir,
+                output_file = self.output_file,
+                log_dir = self.log_dir,
+                log_file = self.log_file,
+                port = str(self.port),
+                torrent_file = self.torrent_file
+                )
+
+        t = Template(self.logging_run_expr)
+        self.logging_run_command = t.substitute(
+                base_path = self.base_path,
+                download_dir = self.download_dir,
+                output_dir = self.output_dir,
+                output_file = self.output_file,
+                log_dir = self.log_dir,
+                log_file = self.log_file,
+                port = str(self.port),
+                torrent_file = self.torrent_file
+                )
+
+        print self.simple_run_command
+        print self.logging_run_command
+       
+    def run_client(self, command):
+
+        # split command
+        args = shlex.split(command)
+      
+        # remove redirectation parameters
+        for i in range(0, len(args)):
+            if args[i].find(">") > -1 :
+                for j in range(i, len(args)):
+                    args.pop(i)
+                break;
+        if(DEBUG):
+            print "BitTorrentClientRun: command =", args
+        
+        log_redirect = open(self.log_dir+"/"+self.log_file,"w")
+        output_redirect = open(self.output_dir+"/"+self.output_file,"w")
+        p=subprocess.Popen(args, shell=False, #does not create sh process
+                            stdout=log_redirect,
+                            stderr=output_redirect)
+        pid = p.pid
+        if(DEBUG):
+            print "BitTorrentClientRun: pid =", pid
+        return [pid, log_redirect, output_redirect]
+        
+
+def main():
+
+    """
+    Test case
+
+    btcr = BitTorrentClientRun("/home/p2p/p2p-clients/transmission",
+            "$base_path/cli/transmissioncli --download-dir $download_dir --port $port $torrent_file > $output_dir/$output_file",
+            "TR_DEBUG=2 $base_path/cli/transmissioncli --download-dir $download_dir --port $port $torrent_file 2> $log_dir/$log_file > $output_dir/$output_file")
+    btcr.config_run("/home/p2p/p2p-dld/transmission", "/home/p2p/p2p-log/transmission", "transmission-fedora.out", "/home/p2p/p2p-log/transmission", "transmission-fedora.log", 10150, "/home/p2p/p2p-meta/fedora.torrent")
+    btcr.start()
+
+       
+    """
+
+
+if __name__ == "__main__":
+    sys.exit(main())
diff --git a/autorun/server/Client.py b/autorun/server/Client.py
new file mode 100644 (file)
index 0000000..ae461cf
--- /dev/null
@@ -0,0 +1,113 @@
+import sys,time, socket
+import pickle
+from Util import *
+MSGLEN = 1024
+DEBUG = True
+class MySocket:
+    def __init__(self, sock=None):
+        if sock is None:
+            self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+        else:
+            self.sock = sock
+
+    def connect(self, host, port):
+        self.sock.connect((host, port))
+        print "connected to %s %s"%(host, port)
+
+    def send_msg(self, msg):
+        totalsent = 0
+        while totalsent < len(msg):
+            sent = self.sock.send(msg[totalsent:])
+            if sent == 0:
+                raise RuntimeError,    "socket connection broken"
+            totalsent = totalsent + sent
+
+    def send_command(self, msg_type, config_data):
+        self.send_msg(msg_type)
+        print "am trimis ", msg_type
+        response = self.recv_msg()
+        if response == ACK_MSG:
+            self.send_dict(config_data)
+            print "am trimis"
+            response = self.recv_msg()
+
+        return response
+
+    def recv_msg(self):
+        msg = ''
+        chunk = self.sock.recv(MSGLEN)
+        if chunk == '':
+            raise RuntimeError,        "socket connection broken"
+        msg = msg + chunk
+        print "am primit ", msg
+        return msg
+
+    # send a pickled dictionary
+    def send_dict(self, data):
+        dumped_data = pickle.dumps(data)       
+        self.send_msg(dumped_data)
+
+# basic test that starts and stops a BT Client
+def test_all_commands(torrent_file):
+    s = MySocket()
+    s.connect(SERVER_HOST, SERVER_PORT)
+    torrent_name = torrent_file[(torrent_file.rfind("/")+1):torrent_file.find(".torrent")];
+
+    start_data_tribler = {
+            CLIENT: TRIBLER, PORT:10150,
+            BASE_DIR:"/home/p2p/p2p-clients/tribler",
+            TORRENT:"/home/p2p/p2p-meta/" + torrent_name+".torrent",
+            DL_DIR: "/home/p2p/p2p-dld/tribler",
+            LOG_DIR: "/home/p2p/p2p-log/tribler",
+            OUT_FILE: torrent_name + ".out", #status messages
+            LOG_FILE: "tribler-" + torrent_name + ".log", #verbose messages
+
+            }
+    start_data_transmission = {
+            CLIENT: TRANSMISSION, PORT:10250,
+            BASE_DIR:"/usr/bin/",
+            TORRENT: "/home/p2p/p2p-meta/" + torrent_name+".torrent",
+            DL_DIR: "/home/p2p/p2p-dld/transmission",
+            LOG_DIR: "/home/p2p/p2p-log/transmission",
+            OUT_FILE: torrent_name + ".out", #status messages
+            LOG_FILE: "transmission-" + torrent_name + ".log", #verbose messages
+
+            }
+
+    start_data_hrktorrent = {
+            CLIENT: HRKTORRENT, PORT:10350,
+            BASE_DIR:"/home/p2p/p2p-clients/hrktorrent",
+            TORRENT: "/home/p2p/p2p-meta/" + torrent_name+".torrent",
+            DL_DIR: "/home/p2p/p2p-dld/hrktorrent",
+            LOG_DIR: "/home/p2p/p2p-log/hrktorrent",
+            OUT_FILE: torrent_name + ".out", #status messages
+            LOG_FILE: "hrktorrent-" + torrent_name + ".log", #verbose messages
+
+
+            }
+    response = s.send_command(START_MSG, start_data_tribler)
+    print response
+    pid = (response.split(" "))[1]
+    print pid
+    s = MySocket()
+    s.connect(SERVER_HOST, SERVER_PORT)
+    time.sleep(100)
+    response = s.send_command(STOP_MSG, pid)
+    print response
+
+def test_send_recv():
+    # test 1
+
+    s.send_msg("hello")
+    # test 2
+    dd = {'a':1, 'b':2}
+    s.send_dict(dd)
+    s.recv_msg()
+
+
+if __name__ == "__main__":
+
+    if len(sys.argv) != 2:
+        print "Usage: python %s <torrent_file>"%sys.argv[0]
+    else:
+        test_all_commands(sys.argv[1])
diff --git a/autorun/server/HrktorrentRun.py b/autorun/server/HrktorrentRun.py
new file mode 100644 (file)
index 0000000..812cf3b
--- /dev/null
@@ -0,0 +1,34 @@
+#!/usr/bin/env python
+
+"""
+ Base class for running libtorrent (hrktorrent) client instances
+ 2010, Razvan Deaconescu, razvan.deaconescu@cs.pub.ro
+"""
+
+import sys
+import os.path
+from BitTorrentClientRun import BitTorrentClientRun
+
+DEBUG = False
+
+
+class HrktorrentRun(BitTorrentClientRun):
+    def __init__(self, base_path):
+        BitTorrentClientRun.__init__(self, base_path,
+                "cd $download_dir && $base_path/hrktorrent --minport$port --maxport$port $torrent_file &> $output_dir/$output_file",
+                "cd $download_dir && $base_path/hrktorrent --minport$port --maxport$port $torrent_file &> $output_dir/$output_file")
+
+
+def main():
+
+    """
+    Test case
+    """
+
+    hr = HrktorrentRun("/home/p2p/p2p-clients/hrktorrent")
+    hr.config_run("/home/p2p/p2p-dld/hrktorrent", "/home/p2p/p2p-log/hrktorrent", "hrktorrent-fedora.out", "/home/p2p/p2p-log/hrktorrent", "hrktorrent-fedora.log", 10150, "/home/p2p/p2p-meta/fedora.torrent")
+    hr.start()
+
+
+if __name__ == "__main__":
+    sys.exit(main())
diff --git a/autorun/server/MainlineRun.py b/autorun/server/MainlineRun.py
new file mode 100644 (file)
index 0000000..ec65599
--- /dev/null
@@ -0,0 +1,34 @@
+#!/usr/bin/env python
+
+"""
+ Base class for running BitTorrent (Mainline) client instances
+ 2010, Razvan Deaconescu, razvan.deaconescu@cs.pub.ro
+"""
+
+import sys
+import os.path
+from BitTorrentClientRun import BitTorrentClientRun
+
+DEBUG = False
+
+
+class MainlineRun(BitTorrentClientRun):
+    def __init__(self, base_path):
+        BitTorrentClientRun.__init__(self, base_path,
+                "$base_path/bittorrent-console.py --save_in $download_dir --display_interval 1 $torrent_file 2> $log_dir/$log_file > $output_dir/$output_file",
+                "$base_path/bittorrent-console.py --save_in $download_dir --display_interval 1 $torrent_file 2> $log_dir/$log_file > $output_dir/$output_file")
+
+
+def main():
+
+    """
+    Test case
+    """
+
+    mr = MainlineRun("/home/p2p/p2p-clients/mainline")
+    mr.config_run("/home/p2p/p2p-dld/mainline", "/home/p2p/p2p-log/mainline", "mainline-fedora.out", "/home/p2p/p2p-log/mainline", "mainline-fedora.log", 10150, "/home/p2p/p2p-meta/fedora.torrent")
+    mr.start()
+
+
+if __name__ == "__main__":
+    sys.exit(main())
diff --git a/autorun/server/Server.py b/autorun/server/Server.py
new file mode 100644 (file)
index 0000000..9976613
--- /dev/null
@@ -0,0 +1,192 @@
+#!/usr/bin/env python
+
+import sys, os, socket 
+import pickle
+import signal
+from daemon import Daemon
+from Util import *
+from Util import SERVER_HOST, SERVER_PORT
+from BitTorrentClientRun import *
+from TransmissionRun import *
+from TriblerRun import *
+
+DEBUG = True
+
+
+class MyDaemon(Daemon):
+
+    ip = ""
+    port = 0
+    BUFFER_SIZE = 4096
+
+    states = {} # keeps track of what kind of message was previously receveid on a socket.
+    processes = {}
+    WAITING_MSG_TYPE = 0
+    WAITING_START_DATA = 3
+    WAITING_STOP_DATA = 4
+    WAITING_STATUS_DATA = 5
+    
+    def __init__(self, pidfile, ip='', port = 0, stdin='/dev/null', stdout='/dev/null', stderr='/dev/null'):
+        Daemon.__init__(self, pidfile, stdin, stdout, stderr)
+        self.ip = ip
+        self.port = port
+
+    def set_address(self, ip):
+        self.ip = ip
+        print "am setat ip ", ip
+    
+    def set_port(self, port):
+        self.port = port
+        print "am setat port ", port
+    
+    def run(self):
+        self.doServer(self.ip, self.port)
+    
+    def recv_pickled_data(self, clientsock):
+        #      while chunk:            
+        #              chunk = clientsock.recv(self.BUFFER_SIZE)
+        #              data += chunk
+        data = clientsock.recv(self.BUFFER_SIZE)
+        dd = pickle.loads(data)        
+        return dd
+
+
+    """ Starts a process for a BitTorrent client and returns its pid.
+        @return: -1, if any error is encountered
+    """
+    def start_bt_client(self, bt_client_data):
+
+        btcr = None
+
+        if bt_client_data[CLIENT] == TRANSMISSION:
+            btcr = TransmissionRun(bt_client_data[BASE_DIR])
+        elif bt_client_data[CLIENT] == TRIBLER:
+            btcr = TriblerRun(bt_client_data[BASE_DIR])
+        
+        else:
+            return -1
+        
+        btcr.config_run(bt_client_data[DL_DIR], bt_client_data[LOG_DIR], 
+             bt_client_data[OUT_FILE], bt_client_data[LOG_DIR],
+             bt_client_data[LOG_FILE], bt_client_data[PORT], 
+             bt_client_data[TORRENT])
+
+        btcr.start()
+        [pid, log_fd, output_fd] = btcr.run_client(btcr.simple_run_command)
+        self.processes[pid] = (log_fd, output_fd)
+        print self.processes[pid]
+        if(DEBUG):
+            print "Server: started client with pid = ", pid
+        return pid
+
+        """Simple test 
+
+        btcr = TransmissionRun("/usr/bin/transmissioncli")
+        btcr.config_run("/home/adriana/p2p/p2p-dld/transmission", 
+                        "/home/adriana/p2p/p2p-log/transmission", 
+                        "scrubs.out", "/home/adriana/p2p/", 
+                        "transmission-scrubs.log", 10150, 
+                        "/home/adriana/p2p/p2p-meta/scrubs.torrent")
+        
+        btcr.start()
+        btcr.run_client(btcr.simple_run_command)
+        """
+
+    def stop_bt_client(self, pid):
+        
+        int_pid = int(pid)
+        os.kill(int_pid, signal.SIGKILL) # kill generates zombies
+        os.wait()
+        self.processes[int_pid][0].close() 
+        self.processes[int_pid][1].close()
+        del self.processes[int_pid] 
+        if(DEBUG):
+            print "Server: killed process with pid = ", pid
+
+    def doServer(self, ip, port):
+
+        serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+        
+        if(DEBUG):
+            print "Server: host ip = %s, port = %d"%(SERVER_HOST,SERVER_PORT)
+        serversocket.bind((ip,port));
+        serversocket.listen(10) #max 10 requests
+        clientsocks = []
+        while(1):
+            if(DEBUG):
+                print "Server: accepting connections"
+            (clientsock, address) = serversocket.accept();
+            if(DEBUG):
+                print "Server: accepted connection from ", address
+            
+            if clientsock not in self.states:
+                self.states[clientsock] = self.WAITING_MSG_TYPE;
+
+            if self.states[clientsock] == self.WAITING_MSG_TYPE:
+                print self.states[clientsock]
+                msg = clientsock.recv(self.BUFFER_SIZE)
+                if(DEBUG):
+                    print "Server: received message:\n", msg
+                msg_types = {
+                    START_MSG: self.WAITING_START_DATA,
+                    STOP_MSG: self.WAITING_STOP_DATA,
+                    STATUS_MSG: self.WAITING_STATUS_DATA
+                }
+                if msg not in  msg_types:
+                    clientsock.send(ERROR_MSG +"wrong message type " + msg)
+                else:
+                    self.states[clientsock] = msg_types[msg]
+                    clientsock.send(ACK_MSG)
+            #else: 
+            print self.states[clientsock]
+
+            if self.states[clientsock] == self.WAITING_START_DATA:
+                bt_client_data = self.recv_pickled_data(clientsock)
+                if(DEBUG):
+                    print "Server: received message:\n", msg
+                client_pid = self.start_bt_client(bt_client_data)
+                clientsock.send(ACK_MSG +" "+ str(client_pid))
+
+            elif self.states[clientsock] == self.WAITING_STOP_DATA:
+                client_pid = self.recv_pickled_data(clientsock)
+                if(DEBUG):
+                    print "Server: received message:\n", msg
+                self.stop_bt_client(client_pid)
+                clientsock.send(ACK_MSG)
+
+            elif self.states[clientsock] == self.WAITING_STATUS_DATA:
+                config = self.recv_pickled_data(clientsock)
+                clientsock.send(ACK_MSG)
+
+            self.states[clientsock] = self.WAITING_MSG_TYPE
+
+            # clientsock.recv(self.BUFFER_SIZE)
+            # recv_pickled_data(clientsock)
+            clientsock.close()
+
+if __name__ == "__main__":
+
+    if len(sys.argv) >= 2:
+        
+        if 'start' == sys.argv[1]:
+            if(len(sys.argv) != 4):
+                print "usage:\n\t %s start <host_ip> <port>" % sys.argv[0]
+                sys.exit(2)
+            daemon = MyDaemon('/tmp/daemon-example.pid', sys.argv[2], int(sys.argv[3]), stdout = '/home/p2p/out', stderr = 'home/p2p/err') 
+            daemon.start()
+        elif 'stop' == sys.argv[1]:
+            daemon = MyDaemon('/tmp/daemon-example.pid') 
+            daemon.stop()
+        elif 'restart' == sys.argv[1]:
+            daemon = MyDaemon('/tmp/daemon-example.pid') 
+            daemon.restart()
+        else:
+            print "Unknown command"
+            sys.exit(2)
+        sys.exit(0)
+    else:
+        print "usage:\n\t %s start <host_ip> <port>" % sys.argv[0]
+        print "\t%s stop|restart "  % sys.argv[0]
+        sys.exit(2)
+
+
diff --git a/autorun/server/Server_NO_DAEMON.py b/autorun/server/Server_NO_DAEMON.py
new file mode 100644 (file)
index 0000000..2745331
--- /dev/null
@@ -0,0 +1,145 @@
+#!/usr/bin/env python
+
+import sys, os, socket 
+import pickle
+import signal
+from daemon import Daemon
+from Util import *
+from Util import SERVER_HOST, SERVER_PORT
+from BitTorrentClientRun import *
+from TransmissionRun import *
+from TriblerRun import *
+BUFFER_SIZE = 4096
+
+states = {} # keeps track of what kind of message was previously receveid on a socket.
+processes = {}
+WAITING_MSG_TYPE = 0
+WAITING_START_DATA = 3
+WAITING_STOP_DATA = 4
+WAITING_STATUS_DATA = 5
+
+DEBUG = True
+
+def recv_pickled_data(clientsock):
+    #  while chunk:            
+    #          chunk = clientsock.recv(BUFFER_SIZE)
+    #          data += chunk
+    data = clientsock.recv(BUFFER_SIZE)
+    dd = pickle.loads(data)    
+    return dd
+
+
+def start_bt_client(bt_client_data):
+
+    btcr = None
+
+    if bt_client_data[CLIENT] == TRANSMISSION:
+        #btcr = TransmissionRun("/usr/bin/transmissioncli")
+        btcr = TransmissionRun(bt_client_data[BASE_DIR])
+    elif bt_client_data[CLIENT] == TRIBLER:
+        btcr = TriblerRun(bt_client_data[BASE_DIR])
+       # btcr = TriblerRun("/home/p2p/p2p-clients/tribler")
+    
+    else:
+        return -1
+    
+    btcr.config_run(bt_client_data[DL_DIR], bt_client_data[LOG_DIR], 
+         bt_client_data[OUT_FILE], bt_client_data[LOG_DIR],
+         bt_client_data[LOG_FILE], bt_client_data[PORT], 
+         bt_client_data[TORRENT])
+
+    btcr.start()
+    [pid, log_fd, output_fd] = btcr.run_client(btcr.simple_run_command)
+    processes[pid] = (log_fd, output_fd)
+    print processes[pid]
+    if(DEBUG):
+        print "Server: started client with pid = ", pid
+    return pid
+
+    """Simple test 
+
+    btcr = TransmissionRun("/usr/bin/transmissioncli")
+    btcr.config_run("/home/adriana/p2p/p2p-dld/transmission", 
+                    "/home/adriana/p2p/p2p-log/transmission", 
+                    "scrubs.out", "/home/adriana/p2p/", 
+                    "transmission-scrubs.log", 10150, 
+                    "/home/adriana/p2p/p2p-meta/scrubs.torrent")
+    
+    btcr.start()
+    btcr.run_client(btcr.simple_run_command)
+    """
+
+def stop_bt_client(pid):
+    
+    int_pid = int(pid)
+    os.kill(int_pid, signal.SIGKILL) # kill generates zombies
+    os.wait()
+    processes[int_pid][0].close() 
+    processes[int_pid][1].close()
+    del processes[int_pid] 
+    if(DEBUG):
+        print "Server: killed process with pid = ", pid
+
+def doServer():
+
+    serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+    if(DEBUG):
+        print "Server: host ip = %s, port = %d"%(SERVER_HOST,SERVER_PORT)
+    serversocket.bind((SERVER_HOST, SERVER_PORT));
+    serversocket.listen(10) #max 10 requests
+    clientsocks = []
+    while(1):
+        if(DEBUG):
+            print "Server: accepting connections"
+        (clientsock, address) = serversocket.accept();
+        if(DEBUG):
+            print "Server: accepted connection from ", address
+        
+        if clientsock not in states:
+            states[clientsock] = WAITING_MSG_TYPE;
+
+        if states[clientsock] == WAITING_MSG_TYPE:
+            print states[clientsock]
+            msg = clientsock.recv(BUFFER_SIZE)
+            if(DEBUG):
+                print "Server: received message:\n", msg
+            msg_types = {
+                START_MSG: WAITING_START_DATA,
+                STOP_MSG: WAITING_STOP_DATA,
+                STATUS_MSG: WAITING_STATUS_DATA
+            }
+            if msg not in  msg_types:
+                clientsock.send(ERROR_MSG +"wrong message type " + msg)
+            else:
+                states[clientsock] = msg_types[msg]
+                clientsock.send(ACK_MSG)
+        #else: 
+        print states[clientsock]
+
+        if states[clientsock] == WAITING_START_DATA:
+            bt_client_data = recv_pickled_data(clientsock)
+            if(DEBUG):
+                print "Server: received message:\n", msg
+            client_pid = start_bt_client(bt_client_data)
+            clientsock.send(ACK_MSG +" "+ str(client_pid))
+
+        elif states[clientsock] == WAITING_STOP_DATA:
+            client_pid = recv_pickled_data(clientsock)
+            if(DEBUG):
+                print "Server: received message:\n", msg
+            stop_bt_client(client_pid)
+            clientsock.send(ACK_MSG)
+
+        elif states[clientsock] == WAITING_STATUS_DATA:
+            config = recv_pickled_data(clientsock)
+            clientsock.send(ACK_MSG)
+
+        states[clientsock] = WAITING_MSG_TYPE
+
+        # clientsock.recv(BUFFER_SIZE)
+        # recv_pickled_data(clientsock)
+        clientsock.close()
+
+if __name__ == "__main__":
+       doServer()      
+
diff --git a/autorun/server/TransmissionRun.py b/autorun/server/TransmissionRun.py
new file mode 100644 (file)
index 0000000..a1953a5
--- /dev/null
@@ -0,0 +1,34 @@
+#!/usr/bin/env python
+
+"""
+ Base class for running Transmission client instances
+ 2010, Razvan Deaconescu, razvan.deaconescu@cs.pub.ro
+"""
+
+import sys
+import os.path
+from BitTorrentClientRun import BitTorrentClientRun
+
+DEBUG = False
+
+
+class TransmissionRun(BitTorrentClientRun):
+    def __init__(self, base_path):
+        BitTorrentClientRun.__init__(self, base_path,
+                "$base_path/transmission --download-dir $download_dir --port $port $torrent_file > $output_dir/$output_file", 
+                "TR_DEBUG=2 $base_path/transmission --download-dir $download_dir --port $port $torrent_file 2> $log_dir/$log_file > $output_dir/$output_file")
+        
+
+def main():
+
+    """
+    Test case
+    """
+
+    tr = TransmissionRun("/home/p2p/p2p-clients/transmission")
+    tr.config_run("/home/p2p/p2p-dld/transmission", "/home/p2p/p2p-log/transmission", "transmission-fedora.out", "/home/p2p/p2p-log/transmission", "transmission-fedora.log", 10150, "/home/p2p/p2p-meta/fedora.torrent")
+    tr.start()
+
+
+if __name__ == "__main__":
+    sys.exit(main())
diff --git a/autorun/server/TriblerRun.py b/autorun/server/TriblerRun.py
new file mode 100644 (file)
index 0000000..8e62760
--- /dev/null
@@ -0,0 +1,71 @@
+#!/usr/bin/env python
+
+"""
+ Base class for running Tribler client instances
+ 2010, Razvan Deaconescu, razvan.deaconescu@cs.pub.ro
+"""
+
+import sys
+import os.path
+from BitTorrentClientRun import BitTorrentClientRun
+
+DEBUG = False
+
+
+class TriblerRun(BitTorrentClientRun):
+    def __init__(self, base_path):
+
+        self.set_PYTHONPATH(base_path)
+        BitTorrentClientRun.__init__(self, base_path,
+                "python $base_path/Tribler/Tools/cmdlinedl.py -o $download_dir -p $port $torrent_file 2> $log_dir/$log_file > $output_dir/$output_file",
+                "python $base_path/Tribler/Tools/cmdlinedl.py -o $download_dir -p $port $torrent_file 2> $log_dir/$log_file > $output_dir/$output_file")
+         
+
+    """
+        Adds lines in cmdlinedl.py that set the PYTHONPATH variable.
+    """
+    def set_PYTHONPATH(self, base_path):
+        filename = base_path + "/Tribler/Tools/cmdlinedl.py"
+        tmp_filename = filename + "_tmp"
+        if not os.path.exists(filename) or not os.path.isfile(filename):
+            print "Error: invalid Tribler path ", filename
+            return
+        f = open(filename, "r");
+        f_copy = open(tmp_filename, "w");
+        import_line = "import sys" 
+        instr_line = "\nsys.path.append('"+base_path+"')\n"
+        exists = False
+        position = -1
+        exists = False
+        for line in f:
+            if line.find("import")>=0 and line.find("sys")>=0 and (not line.find("sys."))>=0:
+                #position = f.tell() + len(line) + 1
+                f_copy.write(line)
+                f_copy.write(instr_line)
+                continue
+            if line == instr_line:
+                exists = True
+                break
+            f_copy.write(line)
+            
+        f_copy.close()
+        f.close()
+        if not exists:
+            os.remove(filename)
+            os.rename(tmp_filename, filename)
+        else: 
+            os.remove(tmp_filename)
+
+def main():
+
+    """
+    Test case
+    """
+
+    tr = TriblerRun("/home/p2p/p2p-clients/tribler")
+    #tr.config_run("/home/p2p/p2p-dld/tribler", "/home/p2p/p2p-log/tribler", "tribler-fedora.out", "/home/p2p/p2p-log/tribler", "tribler-fedora.log", 10150, "/home/p2p/p2p-meta/fedora.torrent")
+    #tr.start()
+
+
+if __name__ == "__main__":
+    sys.exit(main())
diff --git a/autorun/server/VuzeRun.py b/autorun/server/VuzeRun.py
new file mode 100644 (file)
index 0000000..c6ba26e
--- /dev/null
@@ -0,0 +1,34 @@
+#!/usr/bin/env python
+
+"""
+ Base class for running Transmission client instances
+ 2010, Razvan Deaconescu, razvan.deaconescu@cs.pub.ro
+"""
+
+import sys
+import os.path
+from BitTorrentClientRun import BitTorrentClientRun
+
+DEBUG = False
+
+
+class TransmissionRun(BitTorrentClientRun):
+    def __init__(self, base_path):
+        BitTorrentClientRun.__init__(self, base_path,
+                "$base_path/cli/transmissioncli --download-dir $download_dir --port $port $torrent_file > $output_dir/$output_file",
+                "TR_DEBUG=2 $base_path/cli/transmissioncli --download-dir $download_dir --port $port $torrent_file 2> $log_dir/$log_file > $output_dir/$output_file")
+
+
+def main():
+
+    """
+    Test case
+    """
+
+    tr = TransmissionRun("/home/p2p/p2p-clients/transmission")
+    tr.config_run("/home/p2p/p2p-dld/transmission", "/home/p2p/p2p-log/transmission", "transmission-fedora.out", "/home/p2p/p2p-log/transmission", "transmission-fedora.log", 10150, "/home/p2p/p2p-meta/fedora.torrent")
+    tr.start()
+
+
+if __name__ == "__main__":
+    sys.exit(main())
diff --git a/autorun/server/daemon.py b/autorun/server/daemon.py
new file mode 100644 (file)
index 0000000..f371720
--- /dev/null
@@ -0,0 +1,129 @@
+#!/usr/bin/env python
+
+import sys, os, time, atexit
+from signal import SIGTERM 
+
+class Daemon:
+       """
+       A generic daemon class.
+       
+       Usage: subclass the Daemon class and override the run() method
+       """
+       def __init__(self, pidfile, stdin='/dev/null', stdout='/dev/null', stderr='/dev/null'):
+               self.stdin = stdin
+               self.stdout = stdout
+               self.stderr = stderr
+               self.pidfile = pidfile
+       
+       def daemonize(self):
+               """
+               do the UNIX double-fork magic, see Stevens' "Advanced 
+               Programming in the UNIX Environment" for details (ISBN 0201563177)
+               http://www.erlenstar.demon.co.uk/unix/faq_2.html#SEC16
+               """
+               try: 
+                       pid = os.fork() 
+                       if pid > 0:
+                               # exit first parent
+                               sys.exit(0) 
+               except OSError, e: 
+                       sys.stderr.write("fork #1 failed: %d (%s)\n" % (e.errno, e.strerror))
+                       sys.exit(1)
+       
+               # decouple from parent environment
+               os.chdir("/") 
+               os.setsid() 
+               os.umask(0) 
+       
+               # do second fork
+               try: 
+                       pid = os.fork() 
+                       if pid > 0:
+                               # exit from second parent
+                               sys.exit(0) 
+               except OSError, e: 
+                       sys.stderr.write("fork #2 failed: %d (%s)\n" % (e.errno, e.strerror))
+                       sys.exit(1) 
+       
+               # redirect standard file descriptors
+               sys.stdout.flush()
+               sys.stderr.flush()
+               si = file(self.stdin, 'r')
+               so = file(self.stdout, 'a+')
+               se = file(self.stderr, 'a+', 0)
+               os.dup2(si.fileno(), sys.stdin.fileno())
+               os.dup2(so.fileno(), sys.stdout.fileno())
+               os.dup2(se.fileno(), sys.stderr.fileno())
+       
+               # write pidfile
+               atexit.register(self.delpid)
+               pid = str(os.getpid())
+               file(self.pidfile,'w+').write("%s\n" % pid)
+       
+       def delpid(self):
+               os.remove(self.pidfile)
+
+       def start(self):
+               """
+               Start the daemon
+               """
+               # Check for a pidfile to see if the daemon already runs
+               try:
+                       pf = file(self.pidfile,'r')
+                       pid = int(pf.read().strip())
+                       pf.close()
+               except IOError:
+                       pid = None
+       
+               if pid:
+                       message = "pidfile %s already exist. Daemon already running?\n"
+                       sys.stderr.write(message % self.pidfile)
+                       sys.exit(1)
+               
+               # Start the daemon
+               self.daemonize()
+               self.run()
+
+       def stop(self):
+               """
+               Stop the daemon
+               """
+               # Get the pid from the pidfile
+               try:
+                       pf = file(self.pidfile,'r')
+                       pid = int(pf.read().strip())
+                       pf.close()
+               except IOError:
+                       pid = None
+       
+               if not pid:
+                       message = "pidfile %s does not exist. Daemon not running?\n"
+                       sys.stderr.write(message % self.pidfile)
+                       return # not an error in a restart
+
+               # Try killing the daemon process        
+               try:
+                       while 1:
+                               os.kill(pid, SIGTERM)
+                               time.sleep(0.1)
+               except OSError, err:
+                       err = str(err)
+                       if err.find("No such process") > 0:
+                               if os.path.exists(self.pidfile):
+                                       os.remove(self.pidfile)
+                       else:
+                               print str(err)
+                               sys.exit(1)
+
+       def restart(self):
+               """
+               Restart the daemon
+               """
+               self.stop()
+               self.start()
+
+       def run(self):
+               """
+               You should override this method when you subclass Daemon. It will be called after the process has been
+               daemonized by start() or restart().
+               """
diff --git a/autorun/xml/clients.xml b/autorun/xml/clients.xml
new file mode 100644 (file)
index 0000000..f8a805c
--- /dev/null
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<clients>
+    <client id="tribler">
+       <run type="script">
+           <file>Tribler/Tools/cmdlinedl.py</file>
+           <interpreter>python </interpreter>
+           <prefix>PYTHONPATH=.</prefix>
+           <suffix></suffix>
+       </run>
+       <upload_limit_option></upload_limit_option>
+       <download_limit_option></download_limit_option>
+       <port_option>-p</port_option>
+       <logging_dir_option>-l</logging_dir_option>
+       <download_dir_option>-d</download_dir_option>
+    </client>
+    <client id="libtorrent">
+       <run type="executable">
+           <file>hrktorrent</file>
+           <interpreter></interpreter>
+           <prefix></prefix>
+           <suffix></suffix>
+       </run>
+       <port_option>-p</port_option>
+       <download_dir_option>-d</download_dir_option>
+    </client>
+    <client id="transmission">
+       <run type="executable">
+           <file>src/transmission-cli</file>
+           <interpreter></interpreter>
+           <prefix></prefix>
+           <suffix></suffix>
+       </run>
+       <upload_limit_option>-u</upload_limit_option>
+       <download_limit_option>-d</download_limit_option>
+       <port_option>-p</port_option>
+       <logging_dir_option>-l</logging_dir_option>
+       <download_dir_option>-o</download_dir_option>
+    </client>
+</clients>
diff --git a/autorun/xml/nodes.xml b/autorun/xml/nodes.xml
new file mode 100644 (file)
index 0000000..514bb2b
--- /dev/null
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<nodes>
+    <node id="1">
+       <public_address>141.85.224.204</public_address>
+       <public_port>10150</public_port>
+       <public_iface>eth0</public_iface>
+       <private_address>172.16.20.3</private_address>
+       <private_port></private_port>
+       <private_iface>venet0:0</private_iface>
+       <ssh_port>20322</ssh_port>
+       <username>p2p</username>
+       <listen_port>10004</listen_port>
+       <daemon_dir>/home/p2p/cs-p2p-next/bt_comm/server</daemon_dir>
+       <clients>
+           <client id="tribler">
+               <base>/home/p2p/p2p-clients/tribler/</base>
+           </client>
+           <client id="libtorrent">
+               <base>/home/p2p/p2p-clients/libtorrent/</base>
+           </client>
+           <client id="transmission">
+               <base>/home/p2p/p2p-clients/transmission/</base>
+           </client>
+        </clients>
+    </node>
+</nodes>
diff --git a/autorun/xml/swarm.xml b/autorun/xml/swarm.xml
new file mode 100644 (file)
index 0000000..4899737
--- /dev/null
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<swarm>
+    <torrent_file>/home/p2p/p2p-meta/bbt316.torrent</torrent_file>
+    <instance id="1">
+       <node>1</node>
+       <client>tribler</client>
+       <upload_limit>512</upload_limit>
+       <download_limit>256</download_limit>
+       <download_dir>/home/p2p/p2p-dld/tribler</download_dir>
+       <log_dir>/home/p2p/p2p-log/tribler</log_dir>
+       <log_file>tribler-bbt316.log</log_file>
+       <output_dir>/home/p2p/p2p-log/tribler</output_dir>
+       <output_file>tribler-bbt316.out</output_file>
+       <actions>
+           <action type="start" delay="00:05:00" />
+           <action type="stop" delay="00:10:00" />
+           <action type="start" delay="00:15:00" />
+           <action type="stop" delay="00:20:00" />
+           <action type="start" delay="00:25:00" />
+           <action type="start" delay="end" />
+       </actions>
+    </instance>
+</swarm>