Ejemplo n.º 1
0
 def __Connect2Server(self, *targs):
     args = targs[0]; number = args[0]; videohash = args[1];
     self.__connectionLock.acquire(); self.__neighborLock.acquire();
     Neighborhood = lminus(self.__ServerNeighborhood, self.__ServerConnectionIPs)
     potentialconnect = sample(Neighborhood, min(len(Neighborhood),number))
     for eachServer in potentialconnect:
         if self.__NumofConnections < self.__MaxNumConn:     
             if eachServer not in self.__ServerConnectionIPs:           
                 servSock = Mytcpsocket()
                 ack1 = servSock.Connect2Server(eachServer)
                 ack2 = servSock.sendmsg(self.__Addr[1])
                 ack3 = servSock.recvmsg(BUFSIZ)          # receive ACK
                 if ack1 and ack2 and ack3!='closed':
                     self.__NumofConnections += 1
                     self.__ServerConnectionSocks.append(servSock)
                     self.__ServerConnectionIPs.append(eachServer)
                     t = MyThread(self.__download,(servSock,eachServer,videohash),
                                  self.__download.__name__)
                     t.start(); sleep(PROCESS_TIME);
                     self.__downloadthreads.append(t);
                 else:
                     self.__ServerNeighborhood.remove(eachServer)
         else:
             break
     self.__connectionLock.release(); self.__neighborLock.release();
Ejemplo n.º 2
0
 def __Connect2Client(self, number):
     self.__connectionLock.acquire(); self.__neighborLock.acquire();
     Neighborhood = lminus(self.__ClientNeighborhood, self.__ClientConnectionIPs)
     potentialconnect = sample(Neighborhood, min(len(Neighborhood),number))
     for eachClient in potentialconnect:
         if self.__NumofConnections < self.__MaxNumConn:  
             if eachClient not in self.__ClientConnectionIPs:              
                 cliSock = Mytcpsocket()
                 ack1 = cliSock.Connect2Server(eachClient)
                 ack2 = cliSock.sendmsg(self.__Addr[1])
                 ack3 = cliSock.recvmsg(BUFSIZ)          # receive ACK
                 if ack1 and ack2 and ack3!='closed':
                     self.__NumofConnections += 1
                     self.__ClientConnectionSocks.append(cliSock);
                     self.__ClientConnectionIPs.append(eachClient);
                     t = MyThread(self.__upload,(cliSock,eachClient),self.__upload.__name__)
                     self.__UploadThreadsLock.acquire(); self.__UploadThreads.append(t); self.__UploadThreadsLock.release()
                     self.__BWControlBoot.set();               # start BW control
                     self.__RateAllocBoot.set();               # start rate allocation
                     t.start(); sleep(PROCESS_TIME);
                 else:
                     self.__ClientNeighborhood.remove(eachClient)
         else:
             break;
     self.__connectionLock.release(); self.__neighborLock.release();
Ejemplo n.º 3
0
 def __Connect2Client(self, number):
     self.__connectionLock.acquire()
     self.__neighborLock.acquire()
     Neighborhood = lminus(self.__ClientNeighborhood,
                           self.__ClientConnectionIPs)
     potentialconnect = sample(Neighborhood, min(len(Neighborhood), number))
     for eachClient in potentialconnect:
         if self.__NumofConnections < self.__MaxNumConn:
             if eachClient not in self.__ClientConnectionIPs:
                 cliSock = Mytcpsocket()
                 ack1 = cliSock.Connect2Server(eachClient)
                 ack2 = cliSock.sendmsg(self.__Addr[1])
                 ack3 = cliSock.recvmsg(BUFSIZ)  # receive ACK
                 if ack1 and ack2 and ack3 != 'closed':
                     self.__NumofConnections += 1
                     self.__ClientConnectionSocks.append(cliSock)
                     self.__ClientConnectionIPs.append(eachClient)
                     t = MyThread(self.__upload, (cliSock, eachClient),
                                  self.__upload.__name__)
                     self.__UploadThreadsLock.acquire()
                     self.__UploadThreads.append(t)
                     self.__UploadThreadsLock.release()
                     self.__BWControlBoot.set()
                     # start BW control
                     self.__RateAllocBoot.set()
                     # start rate allocation
                     t.start()
                     sleep(PROCESS_TIME)
                 else:
                     self.__ClientNeighborhood.remove(eachClient)
         else:
             break
     self.__connectionLock.release()
     self.__neighborLock.release()
Ejemplo n.º 4
0
 def __Connect2Server(self, *targs):
     args = targs[0]
     number = args[0]
     videohash = args[1]
     self.__connectionLock.acquire()
     self.__neighborLock.acquire()
     Neighborhood = lminus(self.__ServerNeighborhood,
                           self.__ServerConnectionIPs)
     potentialconnect = sample(Neighborhood, min(len(Neighborhood), number))
     for eachServer in potentialconnect:
         if self.__NumofConnections < self.__MaxNumConn:
             if eachServer not in self.__ServerConnectionIPs:
                 servSock = Mytcpsocket()
                 ack1 = servSock.Connect2Server(eachServer)
                 ack2 = servSock.sendmsg(self.__Addr[1])
                 ack3 = servSock.recvmsg(BUFSIZ)  # receive ACK
                 if ack1 and ack2 and ack3 != 'closed':
                     self.__NumofConnections += 1
                     self.__ServerConnectionSocks.append(servSock)
                     self.__ServerConnectionIPs.append(eachServer)
                     t = MyThread(self.__download,
                                  (servSock, eachServer, videohash),
                                  self.__download.__name__)
                     t.start()
                     sleep(PROCESS_TIME)
                     self.__downloadthreads.append(t)
                 else:
                     self.__ServerNeighborhood.remove(eachServer)
         else:
             break
     self.__connectionLock.release()
     self.__neighborLock.release()
Ejemplo n.º 5
0
 def __init__(self, Tracker_Addr=TRACKER_ADDRESS):
     self.__socket = Mytcpsocket()  # a new socket
     self.__Addr = Tracker_Addr  # IP address + port
     self.__MaxNumConn = MAX_TRAC_CONNECTION
     self.__userDict = {}  # connecting addresses of active (estimate) users
     self.__servDict = {
     }  # connecting addresses of active (estimate) helpers
     #self.__servDict[MEDIA_SERVER_ADDRESS] = 1      # the central server
     self.__inputLock = thread.allocate_lock(
     )  # lock for the input variables
     self.__EXIT = 0  # exit the system or not
     self.__movieList = {}  # list of movie names
Ejemplo n.º 6
0
 def __commtotracker(self, *targs):
     ack = False
     while not ack:
         ack = self.__tcpTracSock.Connect2Server(TRACKER_ADDRESS)
         if ack:
             countdown = 0
             while True:
                 if countdown == 0:
                     ack = self.__tcpTracSock.sendmsg('serv+' +
                                                      repr(self.__Addr[1]))
                     newneighborhood = self.__tcpTracSock.recvmsg(BUFSIZ)
                     avaiMovieList = self.__tcpTracSock.recvmsg(BUFSIZ)
                     if (
                             not ack
                     ) or newneighborhood == 'closed' or avaiMovieList == 'closed':
                         ack = False
                         break
                     ACK = 'ACK'
                     if self.__isserver:
                         movienames = ""
                         for fhash, fname in self.__movieList.iteritems():
                             movienames = (movienames + '+' + fname + '#' +
                                           self.__videoStat[fhash][0] +
                                           '#' + self.__videoStat[fhash][1])
                         ack = self.__tcpTracSock.sendmsg('list' +
                                                          movienames)
                         ACK = self.__tcpTracSock.recvmsg(BUFSIZ)
                         if (not ack) or ACK == 'closed':
                             ack = False
                             break
                     else:
                         del self.__videoStat
                         self.__videoStat = {}
                         for eachmovie in avaiMovieList.keys():
                             self.__videoStat[hashlib.md5(
                                 eachmovie).hexdigest(
                                 )] = avaiMovieList[eachmovie]
                     self.__neighborLock.acquire()
                     self.__ClientNeighborhood = union(
                         self.__ClientNeighborhood, newneighborhood)
                     ## might have to set a maximum limit of neighborhood ##
                     self.__neighborLock.release()
                     countdown = OBTAIN_NEIGHBOR_PERIOD / INTERVAL_TRACKER_COMMUNICATION
                 else:
                     ack = self.__tcpTracSock.sendmsg('alive')
                     if not ack:
                         break
                     sleep(INTERVAL_TRACKER_COMMUNICATION)
                     countdown -= 1
         sleep(TRY_INTERVAL)
         del self.__tcpTracSock
         self.__tcpTracSock = Mytcpsocket()
Ejemplo n.º 7
0
    def __init__(self, cwd):
        self.__cwd = cwd  # current working directory
        self.__BootedasUser = True
        self.__tcpTracSock = Mytcpsocket()
        self.__tcpListenSock = Mytcpsocket()
        self.__MaxNumConn = MAX_PEER_CONNECTION
        self.__Addr = (([
            ip for ip in gethostbyname_ex(gethostname())[2]
            if not ip.startswith("127.")
        ][0]), choice(range(50000, 60000)))

        self.__tcpCliSockets = []
        self.__ServerNeighborhood = []
        self.__ServerConnectionIPs = []
        self.__ServerConnectionSocks = []
        self.__NumofConnections = 0
        self.__ExcludedServerAddr = []
        self.__choketimer = 30
        self.__StartWaiting = False

        self.__receivedFile = None  # streaming file object
        self.__avaiMovieList = {}  # available movie list from the tracker
        self.__movieHashNames = {}
        self.__currentvid = 'None'  # current video that is being watched
        self.__NumofChunks = 0
        self.__NumofLeftPieces = 0

        self.__neighborLock = thread.allocate_lock(
        )  # lock for the neighborhood update
        self.__connectionLock = thread.allocate_lock()
        self.__timerLock = thread.allocate_lock()
        self.__streamingStatLock = thread.allocate_lock()
        self.__bufferStatLock = thread.allocate_lock()
        self.__emptyAvailable = threading.Event()
        self.__emptyAvailable.clear()
        # one of the download chunks is waiting for other corresponding threads to finish that chunk
        self.__DownloadWait = threading.Event()
        self.__DownloadWait.clear()
        # wait till download is finished
        self.__BufferFullWait = threading.Event()
        self.__BufferFullWait.clear()
        # buffer too much, wait before download
        self.__BufferEmptyWait = threading.Event()
        self.__BufferEmptyWait.clear()
        # buffer not enough, download from server
        self.__streamingWait = threading.Event()
        self.__streamingWait.clear()
        # wait till buffer is ready to stream
        self.__downloadthreads = []
        self.__EXIT = False
Ejemplo n.º 8
0
 def __WaitforConnection(self, *targs):
     self.__tcpListenSock.InitServSock(self.__Addr, self.__MaxNumConn)
     while True:
         if self.__EXIT:
             return
         (tcpServSock, SERVER_ADDR) = self.__tcpListenSock.WaitforConn()
         self.__connectionLock.acquire()
         servtcpsock = Mytcpsocket(tcpServSock)
         if self.__NumofConnections < self.__MaxNumConn:
             servport = servtcpsock.recvmsg(BUFSIZ)
             ack = servtcpsock.sendmsg('ACK')  # send ACK
             SERVER_SERV_ADDR = (SERVER_ADDR[0], servport)
             if ((SERVER_SERV_ADDR in self.__ServerConnectionIPs)
                     or (SERVER_SERV_ADDR == self.__ExcludedServerAddr)
                     or (not ack) or servport == 'closed'):
                 servtcpsock.close()
             else:
                 self.__ServerConnectionSocks.append(servtcpsock)
                 self.__ServerConnectionIPs.append(SERVER_SERV_ADDR)
                 self.__NumofConnections += 1
                 if VERBOSE:
                     print "...connected from:", SERVER_SERV_ADDR
                 t = MyThread(
                     self.__download,
                     (servtcpsock, SERVER_SERV_ADDR, self.__currentvid),
                     self.__download.__name__)
                 t.start()
                 sleep(PROCESS_TIME)
                 self.__downloadthreads.append(t)
         else:
             servtcpsock.close(
             )  # close if the number of connections exceeds max
         self.__connectionLock.release()
Ejemplo n.º 9
0
 def __commtotracker(self, *targs):
     ack = False
     while not ack:
         if self.__EXIT:
             return
         ack = self.__tcpTracSock.Connect2Server(TRACKER_ADDRESS)
         #print TRACKER_ADDRESS
         if ack:
             countdown = 0
             while True:
                 if self.__EXIT:
                     return
                 if countdown == 0:
                     ack = self.__tcpTracSock.sendmsg('user+' +
                                                      repr(self.__Addr[1]))
                     newneighborhood = self.__tcpTracSock.recvmsg(BUFSIZ)
                     self.__avaiMovieList = self.__tcpTracSock.recvmsg(
                         BUFSIZ)
                     if (
                             not ack
                     ) or newneighborhood == 'closed' or self.__avaiMovieList == 'closed':
                         ack = False
                         break
                     del self.__movieHashNames
                     self.__movieHashNames = {}
                     for eachmovie in self.__avaiMovieList.keys():
                         self.__movieHashNames[hashlib.md5(
                             eachmovie).hexdigest(
                             )] = self.__avaiMovieList[eachmovie]
                     self.__neighborLock.acquire()
                     ## might have to set a maximum limit of neighborhood ##
                     self.__ServerNeighborhood = union(
                         self.__ServerNeighborhood, newneighborhood)
                     self.__ServerNeighborhood = lminus(
                         self.__ServerNeighborhood,
                         self.__ExcludedServerAddr)
                     self.__neighborLock.release()
                     countdown = OBTAIN_NEIGHBOR_PERIOD / INTERVAL_TRACKER_COMMUNICATION
                 else:
                     ack = self.__tcpTracSock.sendmsg('alive')
                     if not ack:
                         break
                     sleep(INTERVAL_TRACKER_COMMUNICATION)
                     countdown -= 1
                     # send alive msg interval
         sleep(TRY_INTERVAL)  # obtain neighborhood/movielist interval
         del self.__tcpTracSock
         self.__tcpTracSock = Mytcpsocket()
Ejemplo n.º 10
0
 def __commtotracker(self, *targs):
     ack = False
     while not ack:
         if self.__EXIT:
             return
         ack = self.__tcpTracSock.Connect2Server(TRACKER_ADDRESS)
         #print TRACKER_ADDRESS
         if ack:
             countdown = 0
             while True:
                 if self.__EXIT:
                     return
                 if countdown == 0:
                     ack = self.__tcpTracSock.sendmsg('user+' + repr(self.__Addr[1]))
                     newneighborhood = self.__tcpTracSock.recvmsg(BUFSIZ)
                     self.__avaiMovieList = self.__tcpTracSock.recvmsg(BUFSIZ)
                     if (not ack) or newneighborhood =='closed' or self.__avaiMovieList == 'closed':
                         ack = False
                         break 
                     del self.__movieHashNames; self.__movieHashNames = {};
                     for eachmovie in self.__avaiMovieList.keys():
                         self.__movieHashNames[hashlib.md5(eachmovie).hexdigest()] = self.__avaiMovieList[eachmovie]
                     self.__neighborLock.acquire()
                     ## might have to set a maximum limit of neighborhood ##
                     self.__ServerNeighborhood = union(self.__ServerNeighborhood,newneighborhood)
                     self.__ServerNeighborhood = lminus(self.__ServerNeighborhood,self.__ExcludedServerAddr)
                     self.__neighborLock.release()
                     countdown = OBTAIN_NEIGHBOR_PERIOD/INTERVAL_TRACKER_COMMUNICATION
                 else:
                     ack = self.__tcpTracSock.sendmsg('alive')
                     if not ack:
                         break
                     sleep(INTERVAL_TRACKER_COMMUNICATION); countdown -= 1; # send alive msg interval 
         sleep(TRY_INTERVAL)       # obtain neighborhood/movielist interval
         del self.__tcpTracSock; self.__tcpTracSock = Mytcpsocket();
Ejemplo n.º 11
0
 def __WaitforConnection(self, *targs):
     self.__tcpListenSock.InitServSock(self.__Addr,self.__MaxNumConn)
     while True:     
         if self.__EXIT:
             return       
         (tcpServSock, SERVER_ADDR) = self.__tcpListenSock.WaitforConn()
         self.__connectionLock.acquire();
         servtcpsock = Mytcpsocket(tcpServSock)
         if self.__NumofConnections < self.__MaxNumConn:
             servport = servtcpsock.recvmsg(BUFSIZ)
             ack = servtcpsock.sendmsg('ACK')                    # send ACK
             SERVER_SERV_ADDR = (SERVER_ADDR[0],servport)
             if ((SERVER_SERV_ADDR in self.__ServerConnectionIPs) or 
                 (SERVER_SERV_ADDR == self.__ExcludedServerAddr) or 
                 (not ack) or servport == 'closed'):
                 servtcpsock.close()
             else:
                 self.__ServerConnectionSocks.append(servtcpsock)
                 self.__ServerConnectionIPs.append(SERVER_SERV_ADDR)
                 self.__NumofConnections += 1
                 if VERBOSE:
                     print "...connected from:", SERVER_SERV_ADDR
                 t = MyThread(self.__download,
                              (servtcpsock,SERVER_SERV_ADDR,self.__currentvid),self.__download.__name__)
                 t.start(); sleep(PROCESS_TIME);
                 self.__downloadthreads.append(t)
         else:
             servtcpsock.close()                                # close if the number of connections exceeds max
         self.__connectionLock.release();
Ejemplo n.º 12
0
 def __WaitforConnection(self, *targs):
     self.__tcpSerSock.InitServSock(self.__Addr,self.__MaxNumConn)
     if VERBOSE:
         print "Waiting for connection..."
     while True:            
         (tcpClientSock, CLIENT_ADDR) = self.__tcpSerSock.WaitforConn()
         self.__connectionLock.acquire();
         clitcpsock = Mytcpsocket(tcpClientSock)
         if self.__NumofConnections < self.__MaxNumConn:
             servport = clitcpsock.recvmsg(BUFSIZ)
             ack = clitcpsock.sendmsg('ACK')
             CLIENT_SERV_ADDR = (CLIENT_ADDR[0],servport)
             if ((CLIENT_SERV_ADDR in self.__ClientConnectionIPs) 
                 or (not ack) or servport == 'closed'):
                 clitcpsock.close()
             else:
                 self.__ClientConnectionSocks.append(clitcpsock);
                 self.__ClientConnectionIPs.append(CLIENT_SERV_ADDR);
                 self.__NumofConnections += 1;
                 if VERBOSE:
                     print "...connected from:", CLIENT_ADDR
                 t = MyThread(self.__upload,(clitcpsock,CLIENT_SERV_ADDR),self.__upload.__name__)
                 self.__UploadThreadsLock.acquire(); self.__UploadThreads.append(t); self.__UploadThreadsLock.release()
                 self.__BWControlBoot.set();               # start BW control
                 self.__RateAllocBoot.set();               # start rate allocation
                 t.start(); sleep(PROCESS_TIME);
         else:
             clitcpsock.close()          # close if the number of connections exceeds max
         self.__connectionLock.release();
Ejemplo n.º 13
0
 def __init__(self, Tracker_Addr = TRACKER_ADDRESS):
     self.__socket = Mytcpsocket()                  # a new socket
     self.__Addr = Tracker_Addr                     # IP address + port
     self.__MaxNumConn = MAX_TRAC_CONNECTION        
     self.__userDict = {}                           # connecting addresses of active (estimate) users
     self.__servDict = {}                           # connecting addresses of active (estimate) helpers
     #self.__servDict[MEDIA_SERVER_ADDRESS] = 1      # the central server
     self.__inputLock = thread.allocate_lock()      # lock for the input variables
     self.__EXIT = 0                                # exit the system or not
     self.__movieList = {}                          # list of movie names
Ejemplo n.º 14
0
 def __commtotracker(self, *targs):
     ack = False
     while not ack:
         ack = self.__tcpTracSock.Connect2Server(TRACKER_ADDRESS)
         if ack:
             countdown = 0
             while True:
                 if countdown == 0:
                     ack = self.__tcpTracSock.sendmsg('serv+' + repr(self.__Addr[1]))
                     newneighborhood = self.__tcpTracSock.recvmsg(BUFSIZ)
                     avaiMovieList = self.__tcpTracSock.recvmsg(BUFSIZ)
                     if (not ack) or newneighborhood=='closed' or avaiMovieList == 'closed':
                         ack = False
                         break
                     ACK = 'ACK'
                     if self.__isserver:
                         movienames = ""
                         for fhash, fname in  self.__movieList.iteritems():
                             movienames = (movienames + '+' + fname 
                                           + '#' + self.__videoStat[fhash][0]
                                           + '#' + self.__videoStat[fhash][1])
                         ack = self.__tcpTracSock.sendmsg('list' + movienames)
                         ACK = self.__tcpTracSock.recvmsg(BUFSIZ)
                         if (not ack) or ACK == 'closed':
                             ack = False
                             break
                     else:
                         del self.__videoStat; self.__videoStat = {};
                         for eachmovie in avaiMovieList.keys():
                             self.__videoStat[hashlib.md5(eachmovie).hexdigest()] = avaiMovieList[eachmovie]    
                     self.__neighborLock.acquire()
                     self.__ClientNeighborhood = union(self.__ClientNeighborhood,newneighborhood)
                     ## might have to set a maximum limit of neighborhood ##
                     self.__neighborLock.release()
                     countdown = OBTAIN_NEIGHBOR_PERIOD/INTERVAL_TRACKER_COMMUNICATION
                 else:
                     ack = self.__tcpTracSock.sendmsg('alive')
                     if not ack:
                         break
                     sleep(INTERVAL_TRACKER_COMMUNICATION); countdown -= 1
         sleep(TRY_INTERVAL)
         del self.__tcpTracSock; self.__tcpTracSock = Mytcpsocket();
Ejemplo n.º 15
0
 def __WaitforConnection(self, *targs):
     self.__tcpSerSock.InitServSock(self.__Addr, self.__MaxNumConn)
     if VERBOSE:
         print "Waiting for connection..."
     while True:
         (tcpClientSock, CLIENT_ADDR) = self.__tcpSerSock.WaitforConn()
         self.__connectionLock.acquire()
         clitcpsock = Mytcpsocket(tcpClientSock)
         if self.__NumofConnections < self.__MaxNumConn:
             servport = clitcpsock.recvmsg(BUFSIZ)
             ack = clitcpsock.sendmsg('ACK')
             CLIENT_SERV_ADDR = (CLIENT_ADDR[0], servport)
             if ((CLIENT_SERV_ADDR in self.__ClientConnectionIPs)
                     or (not ack) or servport == 'closed'):
                 clitcpsock.close()
             else:
                 self.__ClientConnectionSocks.append(clitcpsock)
                 self.__ClientConnectionIPs.append(CLIENT_SERV_ADDR)
                 self.__NumofConnections += 1
                 if VERBOSE:
                     print "...connected from:", CLIENT_ADDR
                 t = MyThread(self.__upload, (clitcpsock, CLIENT_SERV_ADDR),
                              self.__upload.__name__)
                 self.__UploadThreadsLock.acquire()
                 self.__UploadThreads.append(t)
                 self.__UploadThreadsLock.release()
                 self.__BWControlBoot.set()
                 # start BW control
                 self.__RateAllocBoot.set()
                 # start rate allocation
                 t.start()
                 sleep(PROCESS_TIME)
         else:
             clitcpsock.close(
             )  # close if the number of connections exceeds max
         self.__connectionLock.release()
Ejemplo n.º 16
0
 def __init__(self,cwd):
     self.__cwd = cwd                                  # current working directory
     self.__BootedasUser = True
     self.__tcpTracSock = Mytcpsocket()
     self.__tcpListenSock = Mytcpsocket()
     self.__MaxNumConn = MAX_PEER_CONNECTION
     self.__Addr = (([ip for ip in 
                         gethostbyname_ex(gethostname())[2] 
                         if not ip.startswith("127.")][0]), choice(range(50000,60000)))
     
     self.__tcpCliSockets = []           
     self.__ServerNeighborhood = []
     self.__ServerConnectionIPs = []
     self.__ServerConnectionSocks = []           
     self.__NumofConnections = 0
     self.__ExcludedServerAddr = []
     self.__choketimer = 30
     self.__StartWaiting = False
     
     self.__receivedFile = None                        # streaming file object
     self.__avaiMovieList = {}                         # available movie list from the tracker
     self.__movieHashNames = {}
     self.__currentvid = 'None'                        # current video that is being watched
     self.__NumofChunks = 0
     self.__NumofLeftPieces = 0
     
     self.__neighborLock = thread.allocate_lock()      # lock for the neighborhood update
     self.__connectionLock = thread.allocate_lock()
     self.__timerLock = thread.allocate_lock()
     self.__streamingStatLock = thread.allocate_lock()
     self.__bufferStatLock = thread.allocate_lock()
     self.__emptyAvailable = threading.Event(); self.__emptyAvailable.clear();  # one of the download chunks is waiting for other corresponding threads to finish that chunk
     self.__DownloadWait = threading.Event(); self.__DownloadWait.clear();      # wait till download is finished
     self.__BufferFullWait = threading.Event(); self.__BufferFullWait.clear();  # buffer too much, wait before download
     self.__BufferEmptyWait = threading.Event(); self.__BufferEmptyWait.clear();# buffer not enough, download from server
     self.__streamingWait = threading.Event(); self.__streamingWait.clear();    # wait till buffer is ready to stream
     self.__downloadthreads = []
     self.__EXIT = False
Ejemplo n.º 17
0
class MediaClient(object):
    '# Author: Hao Zhang\
     # Created: 02/11/2011\
     # Class: MediaClient - a TCP client  that downloads data from the servers'

    # Initialization -- set up address and port; initilize parameters
    def __init__(self, cwd):
        self.__cwd = cwd  # current working directory
        self.__BootedasUser = True
        self.__tcpTracSock = Mytcpsocket()
        self.__tcpListenSock = Mytcpsocket()
        self.__MaxNumConn = MAX_PEER_CONNECTION
        self.__Addr = (([
            ip for ip in gethostbyname_ex(gethostname())[2]
            if not ip.startswith("127.")
        ][0]), choice(range(50000, 60000)))

        self.__tcpCliSockets = []
        self.__ServerNeighborhood = []
        self.__ServerConnectionIPs = []
        self.__ServerConnectionSocks = []
        self.__NumofConnections = 0
        self.__ExcludedServerAddr = []
        self.__choketimer = 30
        self.__StartWaiting = False

        self.__receivedFile = None  # streaming file object
        self.__avaiMovieList = {}  # available movie list from the tracker
        self.__movieHashNames = {}
        self.__currentvid = 'None'  # current video that is being watched
        self.__NumofChunks = 0
        self.__NumofLeftPieces = 0

        self.__neighborLock = thread.allocate_lock(
        )  # lock for the neighborhood update
        self.__connectionLock = thread.allocate_lock()
        self.__timerLock = thread.allocate_lock()
        self.__streamingStatLock = thread.allocate_lock()
        self.__bufferStatLock = thread.allocate_lock()
        self.__emptyAvailable = threading.Event()
        self.__emptyAvailable.clear()
        # one of the download chunks is waiting for other corresponding threads to finish that chunk
        self.__DownloadWait = threading.Event()
        self.__DownloadWait.clear()
        # wait till download is finished
        self.__BufferFullWait = threading.Event()
        self.__BufferFullWait.clear()
        # buffer too much, wait before download
        self.__BufferEmptyWait = threading.Event()
        self.__BufferEmptyWait.clear()
        # buffer not enough, download from server
        self.__streamingWait = threading.Event()
        self.__streamingWait.clear()
        # wait till buffer is ready to stream
        self.__downloadthreads = []
        self.__EXIT = False

    # Boot as a pure user with prompt
    def bootasuser(self):
        self.__streamingPath = self.__cwd + os.sep + CLIENT_PATH + os.sep
        if not os.path.exists(self.__streamingPath):
            os.makedirs(self.__streamingPath)
        self.__PiecestoDownload = PIECE_IDS  # as a user, download all the pieces
        self.__PiecesperChunk = PIECE_PER_CHUNK
        if VERBOSE:
            print 'User %s goes online at %s' % (self.__Addr, ctime())
        # register to the tracker
        t = MyThread(self.__commtotracker, (1, ),
                     self.__commtotracker.__name__)
        t.start()
        sleep(PROCESS_TIME)
        # choking
        t = MyThread(self.__choke, (1, ), self.__choke.__name__)
        t.start()
        sleep(PROCESS_TIME)
        # enable user prompt
        t = MyThread(
            self.__userprompt, (1, ),
            self.__userprompt.__name__)  # open a new thread for new requests
        t.start()
        sleep(PROCESS_TIME)

    # Boot as a downloader to get packets (as a helper)
    def bootashelper(self, videohash, segID, piecestodownload,
                     excludedServerAddr):
        self.__BootedasUser = False
        self.__ExcludedServerAddr = excludedServerAddr
        self.__PiecestoDownload = piecestodownload  # as a helper, specify pieces to download
        self.__PiecesperChunk = len(piecestodownload)
        self.__streamingPath = self.__cwd + os.sep + SERVER_PATH + os.sep + videohash + os.sep + 'seg' + str(
            segID) + FILE_SUFFIX
        self.__MetaPath = self.__cwd + os.sep + SERVER_PATH + os.sep + videohash + os.sep + 'seg' + str(
            segID) + META_SUFFIX
        self.__BufferFullWait.set()  # no need to buffer download for helper
        #### need a mechanism to control this: need to be either too greedy or too conservative
        self.__BufferEmptyWait.set()
        ######

        # register to the tracker
        t = MyThread(self.__commtotracker, (1, ),
                     self.__commtotracker.__name__)
        t.start()
        sleep(PROCESS_TIME * 2)
        # choking
        t = MyThread(self.__choke, (1, ), self.__choke.__name__)
        t.start()
        sleep(PROCESS_TIME)
        # enable download
        self.__movieInitialize(videohash)
        sleep(PROCESS_TIME)
        self.__DownloadWait.wait()
        # wait until download is finished
        self.__EXIT = True
        return True

    def __bufferControl(self, *targs):
        while True:
            if self.__EXIT:
                return
            self.__streamingStatLock.acquire()
            if self.__streamedNumofChunks >= self.__NumofChunks:
                print self.__NumofChunks, self.__streamedNumofChunks
                self.__streamingWait.set()
                # let the stream break
                self.__streamingStatLock.release()
                break
            if self.__streamingBufferLength < 1:  # less than a second of buffer to play
                self.__streamingWait.clear()  # stop streaming
                self.__BufferEmptyWait.set()
                self.__BufferFullWait.set()
                # start downloading NOW!
            else:
                self.__streamingWait.set()  # let it stream
                if self.__streamingBufferLength >= BUFFER_TOO_MUCH:  # buffer too much
                    self.__BufferFullWait.clear()
                    self.__BufferEmptyWait.clear()  # stop downloading
                elif self.__streamingBufferLength >= BUFFER_LENGTH:
                    self.__BufferEmptyWait.clear()
                elif self.__streamingBufferLength < BUFFER_LENGTH:  # buffer less than required length
                    self.__BufferFullWait.set()  # download from helpers
                    if self.__streamingBufferLength < BUFFER_EMERG_LEFT:  # if less than emergency
                        self.__BufferEmptyWait.set(
                        )  # download from the SERVER
                    else:
                        self.__BufferEmptyWait.clear()
            self.__streamingStatLock.release()
            sleep(BUFFER_CHECK_INTERVAL)

    def __streaming(self, *targs):
        speedup = 1
        while True:
            if self.__EXIT:
                return
            self.__streamingWait.wait()
            ### stream the video NOW for duration xxx ###
            ### Now it is Fake streaming ###
            sleep(1)
            self.__streamingStatLock.acquire()
            if self.__streamingBufferLength > 1:
                self.__streamingBufferLength -= speedup
                print 'subtracted, BufferLength = ', self.__streamingBufferLength
                self.__streamedNumofChunks += speedup * self.__streamingRate / BYTES_PER_CHUNK
            if self.__streamedNumofChunks >= self.__NumofChunks:
                print self.__NumofChunks, self.__streamedNumofChunks
                self.__streamingStatLock.release()
                break
            self.__streamingStatLock.release()
            ################################

    def __choke(self, *targs):
        while True:
            if self.__EXIT:
                return
            self.__connectionLock.acquire()
            if self.__NumofConnections >= self.__MaxNumConn:
                ## re-code the choking algorithm by allocating the probabilities##
                ## START ##
                sockind = choice(range(self.__NumofConnections - 1))
                ## END ##
                self.__ServerConnectionSocks[sockind].close()
                del self.__ServerConnectionSocks[sockind]
                del self.__ServerConnectionIPs[sockind]
                self.__NumofConnections -= 1
            self.__connectionLock.release()
            if self.__NumofConnections < self.__MaxNumConn and self.__currentvid != 'None':
                self.__Connect2Server(
                    (1, self.__currentvid))  # connect to a new peer
            self.__timerLock.acquire()
            sleep(self.__choketimer)
            self.__timerLock.release()

    def __download(self, *targs):
        args = targs[0]
        servSock = args[0]
        servAddr = args[1]
        videohash = args[2]
        self.__DownloadWait.clear()
        while True:
            if videohash == 'None':
                servSock.sendmsg('closed')
                self.__pruneconnections(servSock, servAddr)
                self.__DownloadWait.set()
                return
            ack = servSock.sendmsg(['start',
                                    videohash])  # send which video to watch
            ACK = servSock.recvmsg(BUFSIZ)  # receive acknowledgement
            if not ack or ACK == 'closed':
                self.__pruneconnections(servSock, servAddr)
                self.__DownloadWait.set()
                return
            currentChunkID = -1
            piecesperchunk = self.__PiecesperChunk
            while True:
                if self.__EXIT:
                    return
                if servAddr == MEDIA_SERVER_ADDRESS:  # wait until buffer is too little
                    self.__BufferEmptyWait.wait()
                else:  # wait until buffer is less than a certain threshold
                    self.__BufferFullWait.wait()
                self.__bufferStatLock.acquire()
                if videohash != self.__currentvid:
                    videohash = self.__currentvid
                    self.__bufferStatLock.release()
                    break
                if currentChunkID < self.__bufferheadChunkID:
                    currentChunkID = self.__bufferheadChunkID
                    self.__bufferStatLock.release()
                    ack = servSock.sendmsg(['piece', currentChunkID])
                    #print ack
                    avaiPieceIDsfromServ = servSock.recvmsg(BUFSIZ)
                    #print avaiPieceIDsfromServ
                    if not ack or avaiPieceIDsfromServ == 'closed':
                        self.__pruneconnections(servSock, servAddr)
                        self.__DownloadWait.set()
                        return
                    continue
                avaiPieceIDsfromServ = intersect(
                    avaiPieceIDsfromServ, self.__avaiPieceIDs
                )  # Now I am sure no other peers are giving me the same data
                RequestingSet = lminus(avaiPieceIDsfromServ,
                                       self.__PiecesNowRequested)
                #print RequestingSet, "from", servAddr
                if len(RequestingSet) == 0:
                    if len(
                            lminus(self.__avaiPieceIDs,
                                   self.__PiecesNowRequested)) > 0:
                        ack = servSock.sendmsg(['request'])
                        if not ack:
                            self.__pruneconnections(servSock, servAddr)
                            self.__bufferStatLock.release()
                            self.__DownloadWait.set()
                            return
                    self.__bufferStatLock.release()
                    self.__emptyAvailable.wait(
                        BUFFER_EMERG_LEFT)  # wait until this chunk is over
                    continue
                PiecesToRequest = choice(
                    RequestingSet)  # randomly choose an available piece
                self.__PiecesNowRequested.extend(
                    PiecesToRequest)  # put it into the requesting queue
                self.__bufferStatLock.release()
                ack = servSock.sendmsg(
                    ['content', currentChunkID,
                     PiecesToRequest])  # download the piece
                ACK = servSock.recvmsg(BUFSIZ)
                if ACK == 'OK':
                    data = servSock.recvmsg(
                        BYTES_PER_PIECE,
                        True)  # only receive if server still has it
                else:  # if ACK == 'XX'
                    avaiPieceIDsfromServ.remove(
                        PiecesToRequest)  # otherwise remove it and continue
                    self.__PiecesNowRequested = lminus(
                        self.__PiecesNowRequested, PiecesToRequest)
                    continue
                #print data[0:5]
                print "data from server", servAddr
                self.__bufferStatLock.acquire()
                if videohash != self.__currentvid:  # if no longer watching current video, leave
                    videohash = self.__currentvid
                    self.__bufferStatLock.release()
                    break
                if not ack or data == 'closed':  # check if the connection is still alive
                    self.__pruneconnections(servSock, servAddr)
                    self.__PiecesNowRequested = lminus(
                        self.__PiecesNowRequested, PiecesToRequest)
                    self.__bufferStatLock.release()
                    self.__DownloadWait.set()
                    return
                if currentChunkID < self.__bufferheadChunkID:  # if other processes have already advanced the chunk, then dump it
                    self.__bufferStatLock.release()
                    continue
                # finally I made sure the downloaded pieces is valid and needed
                self.__PiecesNowRequested = lminus(
                    self.__PiecesNowRequested,
                    PiecesToRequest)  # change status requested to available
                self.__avaiPieceIDs = lminus(self.__avaiPieceIDs,
                                             PiecesToRequest)
                self.__bufferPieceIDs.extend(PiecesToRequest)
                self.__bufferContent.append(data)
                if len(self.__bufferPieceIDs
                       ) >= piecesperchunk:  # finished downloading of a chunk
                    sortedIDs, self.__bufferContent = PacketsDecode(
                        self.__bufferContent, self.__bufferPieceIDs)
                    if self.__BootedasUser:
                        ##### feed the buffer to the streaming wrapper #####
                        ##### now just write the file #####
                        self.__receivedFile.write(self.__bufferContent)
                        ##### END #########################
                    else:
                        self.__MetaFile.write(sortedIDs)
                        self.__receivedFile.write(self.__bufferContent)
                    self.__streamingStatLock.acquire()
                    # change streaming buffer length in seconds
                    self.__streamingBufferLength += piecesperchunk * BYTES_PER_PIECE / self.__streamingRate
                    print 'added, BufferLength = ', self.__streamingBufferLength
                    self.__streamingStatLock.release()
                    self.__bufferPieceIDs = []
                    self.__bufferContent = []
                    self.__PiecesNowRequested = []
                    self.__avaiPieceIDs = self.__PiecestoDownload
                    piecesperchunk = self.__PiecesperChunk
                    self.__bufferheadChunkID += 1
                    if self.__bufferheadChunkID == self.__NumofChunks:
                        self.__avaiPieceIDs = intersect(
                            PIECE_IDS[0:self.__NumofLeftPieces],
                            self.__PiecestoDownload)  # last chunk left pieces
                        piecesperchunk = len(self.__avaiPieceIDs)
                    if self.__bufferheadChunkID > self.__NumofChunks or piecesperchunk == 0:
                        self.__currentvid = 'None'  # finish download
                        self.__NumofChunks = 0
                        self.__receivedFile.close()
                        if not self.__BootedasUser:
                            self.__MetaFile.close()
                        self.__DownloadWait.set()
                        # set the wait to finish
                    self.__emptyAvailable.set()
                    # release the available ID empty lock
                    self.__emptyAvailable.clear()
                    # set the lock again for next round
                self.__bufferStatLock.release()

    def __movieInitialize(self, videohash):
        ## dump all current                                # dump the current streaming if possible
        self.__bufferStatLock.acquire()
        if self.__currentvid == videohash:
            self.__bufferStatLock.release()
            return
        #### movie paramter initialization:
        self.__streamingRate = BYTES_PER_CHUNK / BUFFER_LENGTH
        self.__streamingBufferLength = 0  # in units of seconds
        self.__streamedNumofChunks = 0  # number of chunks that are streamed
        self.__bufferheadChunkID = 0  # the chunk ID in front of the buffer
        self.__bufferContent = []  # integer IDs
        self.__bufferPieceIDs = []  # string names
        self.__PiecesNowRequested = []  # pieces that are now requested
        self.__avaiPieceIDs = self.__PiecestoDownload  # initialize available pieces to watch
        self.__streamingWait.clear()
        self.__BufferFullWait.clear()
        self.__BufferEmptyWait.clear()
        if videohash != 'None':  # if a movie was requested
            self.__NumofChunks = self.__movieHashNames[videohash][0]
            self.__NumofLeftPieces = self.__movieHashNames[videohash][1]
            self.__currentvid = videohash
            if self.__receivedFile != None:  # close the opened file
                self.__receivedFile.close()
            if self.__BootedasUser:
                writeFilePath = self.__streamingPath + videohash + '.flv'
                #writeFilePath = self.__streamingPath + 'hancock-tsr2_h480p' + '.flv'
            else:
                writeFilePath = self.__streamingPath
                self.__MetaFile = open(self.__MetaPath, 'w+b')
            self.__receivedFile = open(writeFilePath,
                                       'w+b')  # open a writable file
            if self.__BootedasUser:
                t = MyThread(self.__bufferControl, (1, ),
                             self.__bufferControl.__name__)
                t.start()
                sleep(PROCESS_TIME)
                # start buffer control
                t = MyThread(self.__streaming, (1, ),
                             self.__streaming.__name__)
                # start streaming
                t.start()
                sleep(PROCESS_TIME)
            else:
                self.__BufferEmptyWait.set()
                self.__BufferFullWait.set()
            t = MyThread(self.__Connect2Server, (self.__MaxNumConn, videohash),
                         self.__Connect2Server.__name__)
            t.start()
            sleep(PROCESS_TIME)
            if self.__StartWaiting == False:  # listen to active server to user connections
                self.__StartWaiting = True
                t = MyThread(self.__WaitforConnection, (1, ),
                             self.__WaitforConnection.__name__)
                t.start()
                sleep(PROCESS_TIME)
        else:
            self.__NumofChunks = 0
            self.__NumofLeftPieces = 0
            self.__currentvid = 'None'  # not watching any videos
        self.__bufferStatLock.release()

    def __commtotracker(self, *targs):
        ack = False
        while not ack:
            if self.__EXIT:
                return
            ack = self.__tcpTracSock.Connect2Server(TRACKER_ADDRESS)
            #print TRACKER_ADDRESS
            if ack:
                countdown = 0
                while True:
                    if self.__EXIT:
                        return
                    if countdown == 0:
                        ack = self.__tcpTracSock.sendmsg('user+' +
                                                         repr(self.__Addr[1]))
                        newneighborhood = self.__tcpTracSock.recvmsg(BUFSIZ)
                        self.__avaiMovieList = self.__tcpTracSock.recvmsg(
                            BUFSIZ)
                        if (
                                not ack
                        ) or newneighborhood == 'closed' or self.__avaiMovieList == 'closed':
                            ack = False
                            break
                        del self.__movieHashNames
                        self.__movieHashNames = {}
                        for eachmovie in self.__avaiMovieList.keys():
                            self.__movieHashNames[hashlib.md5(
                                eachmovie).hexdigest(
                                )] = self.__avaiMovieList[eachmovie]
                        self.__neighborLock.acquire()
                        ## might have to set a maximum limit of neighborhood ##
                        self.__ServerNeighborhood = union(
                            self.__ServerNeighborhood, newneighborhood)
                        self.__ServerNeighborhood = lminus(
                            self.__ServerNeighborhood,
                            self.__ExcludedServerAddr)
                        self.__neighborLock.release()
                        countdown = OBTAIN_NEIGHBOR_PERIOD / INTERVAL_TRACKER_COMMUNICATION
                    else:
                        ack = self.__tcpTracSock.sendmsg('alive')
                        if not ack:
                            break
                        sleep(INTERVAL_TRACKER_COMMUNICATION)
                        countdown -= 1
                        # send alive msg interval
            sleep(TRY_INTERVAL)  # obtain neighborhood/movielist interval
            del self.__tcpTracSock
            self.__tcpTracSock = Mytcpsocket()

    def __WaitforConnection(self, *targs):
        self.__tcpListenSock.InitServSock(self.__Addr, self.__MaxNumConn)
        while True:
            if self.__EXIT:
                return
            (tcpServSock, SERVER_ADDR) = self.__tcpListenSock.WaitforConn()
            self.__connectionLock.acquire()
            servtcpsock = Mytcpsocket(tcpServSock)
            if self.__NumofConnections < self.__MaxNumConn:
                servport = servtcpsock.recvmsg(BUFSIZ)
                ack = servtcpsock.sendmsg('ACK')  # send ACK
                SERVER_SERV_ADDR = (SERVER_ADDR[0], servport)
                if ((SERVER_SERV_ADDR in self.__ServerConnectionIPs)
                        or (SERVER_SERV_ADDR == self.__ExcludedServerAddr)
                        or (not ack) or servport == 'closed'):
                    servtcpsock.close()
                else:
                    self.__ServerConnectionSocks.append(servtcpsock)
                    self.__ServerConnectionIPs.append(SERVER_SERV_ADDR)
                    self.__NumofConnections += 1
                    if VERBOSE:
                        print "...connected from:", SERVER_SERV_ADDR
                    t = MyThread(
                        self.__download,
                        (servtcpsock, SERVER_SERV_ADDR, self.__currentvid),
                        self.__download.__name__)
                    t.start()
                    sleep(PROCESS_TIME)
                    self.__downloadthreads.append(t)
            else:
                servtcpsock.close(
                )  # close if the number of connections exceeds max
            self.__connectionLock.release()

    def __Connect2Server(self, *targs):
        args = targs[0]
        number = args[0]
        videohash = args[1]
        self.__connectionLock.acquire()
        self.__neighborLock.acquire()
        Neighborhood = lminus(self.__ServerNeighborhood,
                              self.__ServerConnectionIPs)
        potentialconnect = sample(Neighborhood, min(len(Neighborhood), number))
        for eachServer in potentialconnect:
            if self.__NumofConnections < self.__MaxNumConn:
                if eachServer not in self.__ServerConnectionIPs:
                    servSock = Mytcpsocket()
                    ack1 = servSock.Connect2Server(eachServer)
                    ack2 = servSock.sendmsg(self.__Addr[1])
                    ack3 = servSock.recvmsg(BUFSIZ)  # receive ACK
                    if ack1 and ack2 and ack3 != 'closed':
                        self.__NumofConnections += 1
                        self.__ServerConnectionSocks.append(servSock)
                        self.__ServerConnectionIPs.append(eachServer)
                        t = MyThread(self.__download,
                                     (servSock, eachServer, videohash),
                                     self.__download.__name__)
                        t.start()
                        sleep(PROCESS_TIME)
                        self.__downloadthreads.append(t)
                    else:
                        self.__ServerNeighborhood.remove(eachServer)
            else:
                break
        self.__connectionLock.release()
        self.__neighborLock.release()

    def __userprompt(self, *args):
        while True:
            if self.__EXIT:
                return
            userinput = raw_input(
                '<<<Select a function>>>:\n[-1] Exit\n[1] Watch a Movie\n[2] Print Neighbors\n[3] Print Connections\nYour choice>> '
            )
            if userinput == '1':
                numofmovies = len(self.__avaiMovieList)
                if numofmovies == 0:
                    print 'No movies to watch yet!'
                    continue
                print '<<<Select a movie>>>:'
                print '#. <<Go back>>'
                print '0. <<Stop the current movie>>'
                for i, fname in enumerate(self.__avaiMovieList):
                    print repr(i + 1) + '. ' + fname
                input = raw_input('Your choice>> ')
                if input == '#':  # if the user wants to go back
                    pass
                elif input >= '0' and input <= str(numofmovies):
                    movieID = int(input) - 1
                    if movieID >= 0:  # watch a movie
                        for i, eachmovie in enumerate(self.__avaiMovieList):
                            if i == movieID:
                                videohash = hashlib.md5(eachmovie).hexdigest()
                                break
                    else:
                        videohash = 'None'  # stop watching the current movie
                    self.__movieInitialize(
                        videohash)  # initialize movie download and watching
            elif userinput == '2':
                self.__printAllNeighbors()
            elif userinput == '3':
                self.__printAllConnections()
            elif userinput == '-1':
                self.__EXIT = True
                return
            else:
                pass

    def __pruneconnections(self, tcpsock, Addr):
        self.__connectionLock.acquire()
        print tcpsock, Addr
        print self.__ServerConnectionSocks
        self.__ServerConnectionSocks.remove(tcpsock)
        self.__ServerConnectionIPs.remove(Addr)
        self.__NumofConnections -= 1
        self.__connectionLock.release()

    def __closeAllconnections(self):
        self.__connectionLock.acquire()
        for connection in self.__ServerConnectionSocks:
            connection.close()
        self.__ServerConnectionSocks = []
        self.__ServerConnectionIPs = []
        self.__NumofConnections = 0
        self.__connectionLock.release()

    def __printAllNeighbors(self):
        for eachNeighbor in self.__ServerNeighborhood:
            print eachNeighbor

    def __printAllConnections(self):
        for eachConnectionIP in self.__ServerConnectionIPs:
            print eachConnectionIP
        for eachConnectionSock in self.__ServerConnectionSocks:
            print eachConnectionSock
Ejemplo n.º 18
0
class MediaServer(object):
    '# Author: Hao Zhang\
     # Created: 02/11/2011\
     # Class: MediaServer - a TCP server that uploads data to users'

    def __init__(self, cwd, IS_SERVER=1):
        self.__cwd = cwd  # current working directory
        self.__isserver = IS_SERVER  # I mean the True server, not helper
        self.__tcpSerSock = Mytcpsocket()  # initiate server socket
        self.__tcpTracSock = Mytcpsocket()  # initiate tracker socket
        self.__PATH = self.__cwd + os.sep + SERVER_PATH + os.sep  # set up video caching directory
        if not os.path.exists(self.__PATH):
            os.makedirs(self.__PATH)

        # movieList: vhash: vname; videoDict: vhash: vpath; videoStat: vhash: [NumofChunks, NumofLeftOverPieces]
        self.__movieList = {}
        self.__videoDict = {}
        self.__videoStat = {}
        # storeAlloc: vhash: vsize; storePrices: vhash: vprice
        self.__storeAlloc = {}
        self.__storePrices = {}
        # mediaReaders: vhash: [a list of open file readers for vhash]; mediaUpdaters: vhash: file writer
        self.__mediaReaders = {}
        self.__mediaUpdaters = {}

        if IS_SERVER:
            self.__MaxNumConn = MAX_SERV_CONNECTION
            self.__Addr = MEDIA_SERVER_ADDRESS
            # read all the movies and convert newly added movies
            f = open(self.__PATH + 'movielist.txt', 'r+')
            allLines = f.readlines()
            f.close()
            for eachmovie in allLines:
                moviename = eachmovie.split('\n')[0]
                self.__movieList[hashlib.md5(
                    moviename).hexdigest()] = moviename  #vhash: vname
            dirList = os.listdir(self.__PATH)
            for dname in dirList:
                if (
                        not os.path.isdir(self.__PATH + dname)
                ) and dname != 'movielist.txt':  # if video not converted, convert
                    hashname = hashlib.md5(dname.split('.')[0]).hexdigest()
                    if (hashname in self.__movieList
                            and not hashname in dirList):
                        videopath = self.__PATH + hashname
                        os.makedirs(videopath)
                        self.__convertVideo(videopath + os.sep, self.__PATH +
                                            dname)  # convert the video
            dirList = os.listdir(self.__PATH)
            for dname in dirList:
                if os.path.isdir(self.__PATH + dname):
                    videopath = self.__PATH + dname + os.sep
                    if dname in self.__movieList:
                        self.__videoDict[dname] = videopath  # vhash: vpath
                        f = open(videopath + 'length', 'rb')
                        dt = f.readlines()
                        self.__videoStat[dname] = dt[0].split(',')
                        # vhash: [NumofChunks, NumofLeftoverPieces]
                        self.__mediaReaders[dname] = []
                    else:
                        print videopath  # not in list, to be deleted
                        shutil.rmtree(videopath)
        else:
            self.__MaxNumConn = MAX_PEER_CONNECTION
            # need to implement NAT traversal
            ##########start here############
            self.__Addr = (([
                ip for ip in gethostbyname_ex(gethostname())[2]
                if not ip.startswith("127.")
            ][0]), choice(range(50000, 60000)))
            ##########end   here############
            dirList = os.listdir(self.__PATH)
            for dname in dirList:
                if os.path.isdir(self.__PATH + dname):
                    videopath = self.__PATH + dname + os.sep
                    self.__videoDict[dname] = videopath
                    self.__mediaReaders[dname] = []
                    self.__mediaUpdaters[dname] = MediaFileWrapper(
                        videopath, False)  # write access
                    self.__storeAlloc[dname] = 0
                    self.__storePrices[dname] = 0

        self.__ClientNeighborhood = []
        self.__NumofConnections = 0
        self.__ClientConnectionIPs = []
        self.__ClientConnectionSocks = []
        self.__choketimer = 30

        self.__uploadBW = 0  # KB/sec
        self.__uploadedBytes = 0  # uploaded bytes in a second

        self.__UploadThreads = [
        ]  # upload threads. used to control UploadBWControl

        self.__neighborLock = thread.allocate_lock()
        self.__connectionLock = thread.allocate_lock()
        self.__timerLock = thread.allocate_lock()
        self.__rateAllocLock = thread.allocate_lock()
        self.__mediaReaderLock = thread.allocate_lock()
        self.__uploadStatLock = thread.allocate_lock()
        self.__UploadThreadsLock = thread.allocate_lock()
        self.__BWControlBoot = threading.Event()
        self.__BWControlBoot.clear()
        # we don't need BW control all the time
        self.__uploadBWExceed = threading.Event()
        self.__uploadBWExceed.clear()
        self.__RateAllocBoot = threading.Event()
        self.__RateAllocBoot.clear()
        # we don't need rate allocation all the time

    def boot(self, uploadBW):
        self.__uploadBW = uploadBW  # force a virtual upload bandwidth; for testing reasons
        if VERBOSE:
            print 'Server %s goes online at %s' % (self.__Addr, ctime())
        ####### This is fake, just for testing purpose ################
        t = MyThread(self.__uploadBWControl, (1, ),
                     self.__uploadBWControl.__name__)
        t.start()
        sleep(PROCESS_TIME)
        # rate allocation
        if not self.__isserver:
            t = MyThread(self.__rateallocation, (1, ),
                         self.__rateallocation.__name__)
            t.start()
            sleep(PROCESS_TIME)
        # register to the tracker
        t = MyThread(self.__commtotracker, (1, ),
                     self.__commtotracker.__name__)
        t.start()
        sleep(PROCESS_TIME)
        # listen to passive connections
        t = MyThread(self.__WaitforConnection, (1, ),
                     self.__WaitforConnection.__name__)
        t.start()
        sleep(PROCESS_TIME)
        # actively connect to client
        t = MyThread(self.__Connect2Client, self.__MaxNumConn,
                     self.__Connect2Client.__name__)
        t.start()
        sleep(PROCESS_TIME)
        # choking
        t = MyThread(self.__choke, (1, ), self.__choke.__name__)
        t.start()
        sleep(PROCESS_TIME)
        # user prompt
        t = MyThread(
            self.__userprompt, (1, ),
            self.__userprompt.__name__)  # open a new thread for new requests
        t.start()
        sleep(PROCESS_TIME)

    # This is an artificial upload BW control mechanism; only used for debugging purpose
    def __uploadBWControl(self, *targs):
        checkInterval = 0.1
        while True:
            self.__BWControlBoot.wait()
            # wait till there is at least one upload thread running
            self.__uploadStatLock.acquire()
            exceededBytesPerInterval = self.__uploadedBytes - checkInterval * self.__uploadBW
            self.__uploadStatLock.release()
            if exceededBytesPerInterval > 0:
                self.__uploadBWExceed.clear()
                ## fake wait to get more upload BW
                print 'exceeded'
                sleep(exceededBytesPerInterval / self.__uploadBW)
                print 'sleep over'
            # if there does not exist excessive bytes, the uploadBW will expire
            #print self.__uploadedBytes
            self.__uploadStatLock.acquire()
            self.__uploadedBytes = 0
            self.__uploadStatLock.release()
            self.__uploadBWExceed.set()
            sleep(checkInterval)  # check every second
            self.__UploadThreadsLock.acquire()
            ThreadstoRemove = []
            for eachThread in self.__UploadThreads:
                if not eachThread.isAlive():
                    ThreadstoRemove.append(eachThread)
            for eachRemoval in ThreadstoRemove:
                self.__UploadThreads.remove(eachRemoval)
            if len(self.__UploadThreads) == 0:
                self.__BWControlBoot.clear(
                )  # if no threads are running, stop uploadBW control thread
            self.__UploadThreadsLock.release()

        return

    def __choke(self, *targs):
        while True:
            self.__connectionLock.acquire()
            if self.__NumofConnections >= self.__MaxNumConn:
                ## re-code the choking algorithm by allocating the probabilities##
                ## START ##
                sockind = choice(range(self.__NumofConnections - 1))
                ## END ##
                self.__ClientConnectionSocks[sockind].close()
                del self.__ClientConnectionSocks[sockind]
                del self.__ClientConnectionIPs[sockind]
                self.__NumofConnections -= 1
            self.__connectionLock.release()
            if self.__NumofConnections < self.__MaxNumConn:
                self.__Connect2Client(1)  # connect to a new peer
            self.__timerLock.acquire()
            sleep(self.__choketimer)
            self.__timerLock.release()

    def __upload(self, *targs):
        args = targs[0]
        myClisock = args[0]
        cliAddr = args[1]
        ack = True
        avaPieces = None
        ClientFile = None
        while True:
            self.__BWControlBoot.set()
            self.__RateAllocBoot.set()
            data = myClisock.recvmsg(BUFSIZ)
            print data
            if data[0] == 'start':
                videohash = data[1]  # receive movie hash name
                if not videohash in self.__videoDict.keys(
                ):  # this will happen for helpers only. Server needs all videos
                    print self.__videoDict
                    os.makedirs(self.__PATH + videohash)
                    self.__videoDict[
                        videohash] = self.__PATH + videohash + os.sep
                    self.__mediaReaderLock.acquire()
                    self.__mediaReaders[videohash] = []
                    self.__mediaReaderLock.release()
                    if not self.__isserver:
                        self.__mediaUpdaters[videohash] = MediaFileWrapper(
                            self.__videoDict[videohash], False)  # write access
                        self.__rateAllocLock.acquire()
                        self.__storeAlloc[videohash] = 0
                        self.__storePrices[videohash] = 0
                        self.__rateAllocLock.release()
                ClientFile = MediaFileWrapper(self.__videoDict[videohash])
                self.__mediaReaders[videohash].append(
                    ClientFile)  # add the file reader
                myClisock.sendmsg('ACK')  # send ack
            elif data[0] == 'piece':
                if not self.__isserver:
                    if avaPieces != None:
                        if len(avaPieces) > 0:  # more video than needed
                            self.__rateAllocLock.acquire()
                            self.__storePrices[videohash] -= 1  # minus a token
                            print self.__storePrices
                            self.__rateAllocLock.release()
                        else:
                            pass
                avaPieces = ClientFile.getPieceIdbyChunk(data[1])
                ack = myClisock.sendmsg(avaPieces)
                print avaPieces
            elif data[0] == 'content':
                ChunkID, PieceID = data[1], data[2]
                datamsg = ClientFile.getPiecebyId(ChunkID, PieceID)
                if datamsg != None:  # found the piece
                    ack = myClisock.sendmsg('OK')
                    ## this is a fake constraint on upBW; only for testing purpose
                    self.__uploadBWExceed.wait()
                    ##############################################################
                    ack = myClisock.sendmsg(datamsg, True)
                    self.__uploadStatLock.acquire()
                    self.__uploadedBytes += BYTES_PER_PIECE
                    self.__uploadStatLock.release()
                    avaPieces = avaPieces.lstrip(
                        PieceID)  # remove the piece that is uploaded
                else:
                    ack = myClisock.sendmsg('XX')  # send out a none message
            elif data[0] == 'request':
                if not self.__isserver:
                    if avaPieces != None:
                        if len(avaPieces) == 0:  # could have more video
                            self.__rateAllocLock.acquire()
                            self.__storePrices[videohash] += 1  # plus a token
                            print self.__storePrices
                            self.__rateAllocLock.release()
            if not ack or data == 'closed':
                self.__pruneconnections(myClisock, cliAddr)
                if ClientFile != None:
                    ClientFile.closeAll()
                    self.__mediaReaderLock.acquire()
                    self.__mediaReaders[videohash].remove(ClientFile)
                    self.__mediaReaderLock.release()
                break

    def __download(self, vhashname, segID, pieceIDs):
        helper = MediaClient(self.__cwd)
        Success = helper.bootashelper(vhashname, segID, pieceIDs, self.__Addr)
        del helper
        return Success

    def __rateallocation(self, *targs):
        while True:
            self.__RateAllocBoot.wait()
            self.__rateAllocLock.acquire()
            if len(self.__storeAlloc) != 0:
                totalsiz = 0
                for vhash in self.__storeAlloc.keys():
                    self.__storeAlloc[vhash] = getFolderSize(
                        self.__videoDict[vhash])
                    totalsiz += self.__storeAlloc[
                        vhash]  # calculate the current total size
                pricevideos = zip(self.__storePrices.values(),
                                  self.__storePrices.keys())
                pricevideos.sort()
                sortedValues, sortedVideos = zip(*pricevideos)
                low = 0
                high = len(sortedValues) - 1
                self.__rateAllocLock.release()
                while low <= high:
                    if totalsiz < STORAGE_CAP:
                        if sortedValues[high] > 0:
                            totalsiz += self.__storageupdate(
                                sortedVideos[low],
                                totalsiz)  # ++ storage of high
                            high -= 1
                            continue
                        else:
                            break
                            # no update because not needed
                    if (abs(
                            sortedValues[low]
                    ) < ST_ALLOC_TH  # no update because it does not satisfy threshold
                            or abs(sortedValues[high]) < ST_ALLOC_TH):
                        break
                    if self.__mediaUpdaters[
                            sortedVideos[low]].getNumofSeg() <= 0:
                        low += 1
                        continue
                    if self.__mediaUpdaters[
                            sortedVideos[high]].getNumofSeg() >= SEG_PER_CHUNK:
                        high -= 1
                        continue
                    if sortedValues[low] < 0:
                        totalsiz += self.__storageupdate(
                            sortedVideos[low], totalsiz,
                            False)  # -- storage of low
                    if sortedValues[high] > 0:
                        totalsiz += self.__storageupdate(
                            sortedVideos[low], totalsiz)
                        # ++ storage of high
                self.__rateAllocLock.acquire()
                for vhash in self.__storePrices.keys():
                    self.__storePrices[vhash] = 0  # clear
                #self.__rateAllocLock.release();
            self.__rateAllocLock.release()
            sleep(INTERVAL_RATEALLOC)
            # don't need rate allocation when no download request is present
            self.__UploadThreadsLock.acquire()
            ThreadstoRemove = []
            for eachThread in self.__UploadThreads:
                if not eachThread.isAlive():
                    ThreadstoRemove.append(eachThread)
            for eachRemoval in ThreadstoRemove:
                self.__UploadThreads.remove(eachRemoval)
            if len(self.__UploadThreads) == 0:
                self.__RateAllocBoot.clear(
                )  # if no threads are running, stop rate allocation thread
            self.__UploadThreadsLock.release()

    # perform the storage add or removal given a video name
    def __storageupdate(self, vhashname, totalsiz, added=True):
        mul = 1
        if added:
            pieceIDs = self.__mediaUpdaters[vhashname].getNewPieceIDs()
            segID = self.__mediaUpdaters[vhashname].getNumofSeg() + 1
            rsize = self.__videoStat[vhashname][
                0] * BYTES_PER_CHUNK / SEG_PER_CHUNK
            if rsize + totalsiz < STORAGE_CAP:  # write if not exceed storage limit
                if not self.__download(vhashname, segID,
                                       pieceIDs):  # download data
                    rsize = 0
            else:
                rsize = 0
        else:
            mul = -1
        # the update process is self-locked because the MediaFileWrapper itself is a synchronized process
        UpdateSuccess = True
        self.__mediaReaderLock.acquire()
        for eachClientFile in self.__mediaReaders[vhashname]:
            UpdateSuccess = UpdateSuccess and eachClientFile.UpdateAccess(
                added)  # update file object for each peer
        self.__mediaReaderLock.release()
        self.__mediaUpdaters[vhashname].UpdateAccess(
            added)  # update file access
        if not added and UpdateSuccess:  # wait for close() before removal
            rsize = self.__mediaUpdaters[vhashname].removeSegment()
        return rsize * mul

    def __commtotracker(self, *targs):
        ack = False
        while not ack:
            ack = self.__tcpTracSock.Connect2Server(TRACKER_ADDRESS)
            if ack:
                countdown = 0
                while True:
                    if countdown == 0:
                        ack = self.__tcpTracSock.sendmsg('serv+' +
                                                         repr(self.__Addr[1]))
                        newneighborhood = self.__tcpTracSock.recvmsg(BUFSIZ)
                        avaiMovieList = self.__tcpTracSock.recvmsg(BUFSIZ)
                        if (
                                not ack
                        ) or newneighborhood == 'closed' or avaiMovieList == 'closed':
                            ack = False
                            break
                        ACK = 'ACK'
                        if self.__isserver:
                            movienames = ""
                            for fhash, fname in self.__movieList.iteritems():
                                movienames = (movienames + '+' + fname + '#' +
                                              self.__videoStat[fhash][0] +
                                              '#' + self.__videoStat[fhash][1])
                            ack = self.__tcpTracSock.sendmsg('list' +
                                                             movienames)
                            ACK = self.__tcpTracSock.recvmsg(BUFSIZ)
                            if (not ack) or ACK == 'closed':
                                ack = False
                                break
                        else:
                            del self.__videoStat
                            self.__videoStat = {}
                            for eachmovie in avaiMovieList.keys():
                                self.__videoStat[hashlib.md5(
                                    eachmovie).hexdigest(
                                    )] = avaiMovieList[eachmovie]
                        self.__neighborLock.acquire()
                        self.__ClientNeighborhood = union(
                            self.__ClientNeighborhood, newneighborhood)
                        ## might have to set a maximum limit of neighborhood ##
                        self.__neighborLock.release()
                        countdown = OBTAIN_NEIGHBOR_PERIOD / INTERVAL_TRACKER_COMMUNICATION
                    else:
                        ack = self.__tcpTracSock.sendmsg('alive')
                        if not ack:
                            break
                        sleep(INTERVAL_TRACKER_COMMUNICATION)
                        countdown -= 1
            sleep(TRY_INTERVAL)
            del self.__tcpTracSock
            self.__tcpTracSock = Mytcpsocket()

    def __Connect2Client(self, number):
        self.__connectionLock.acquire()
        self.__neighborLock.acquire()
        Neighborhood = lminus(self.__ClientNeighborhood,
                              self.__ClientConnectionIPs)
        potentialconnect = sample(Neighborhood, min(len(Neighborhood), number))
        for eachClient in potentialconnect:
            if self.__NumofConnections < self.__MaxNumConn:
                if eachClient not in self.__ClientConnectionIPs:
                    cliSock = Mytcpsocket()
                    ack1 = cliSock.Connect2Server(eachClient)
                    ack2 = cliSock.sendmsg(self.__Addr[1])
                    ack3 = cliSock.recvmsg(BUFSIZ)  # receive ACK
                    if ack1 and ack2 and ack3 != 'closed':
                        self.__NumofConnections += 1
                        self.__ClientConnectionSocks.append(cliSock)
                        self.__ClientConnectionIPs.append(eachClient)
                        t = MyThread(self.__upload, (cliSock, eachClient),
                                     self.__upload.__name__)
                        self.__UploadThreadsLock.acquire()
                        self.__UploadThreads.append(t)
                        self.__UploadThreadsLock.release()
                        self.__BWControlBoot.set()
                        # start BW control
                        self.__RateAllocBoot.set()
                        # start rate allocation
                        t.start()
                        sleep(PROCESS_TIME)
                    else:
                        self.__ClientNeighborhood.remove(eachClient)
            else:
                break
        self.__connectionLock.release()
        self.__neighborLock.release()

    def __WaitforConnection(self, *targs):
        self.__tcpSerSock.InitServSock(self.__Addr, self.__MaxNumConn)
        if VERBOSE:
            print "Waiting for connection..."
        while True:
            (tcpClientSock, CLIENT_ADDR) = self.__tcpSerSock.WaitforConn()
            self.__connectionLock.acquire()
            clitcpsock = Mytcpsocket(tcpClientSock)
            if self.__NumofConnections < self.__MaxNumConn:
                servport = clitcpsock.recvmsg(BUFSIZ)
                ack = clitcpsock.sendmsg('ACK')
                CLIENT_SERV_ADDR = (CLIENT_ADDR[0], servport)
                if ((CLIENT_SERV_ADDR in self.__ClientConnectionIPs)
                        or (not ack) or servport == 'closed'):
                    clitcpsock.close()
                else:
                    self.__ClientConnectionSocks.append(clitcpsock)
                    self.__ClientConnectionIPs.append(CLIENT_SERV_ADDR)
                    self.__NumofConnections += 1
                    if VERBOSE:
                        print "...connected from:", CLIENT_ADDR
                    t = MyThread(self.__upload, (clitcpsock, CLIENT_SERV_ADDR),
                                 self.__upload.__name__)
                    self.__UploadThreadsLock.acquire()
                    self.__UploadThreads.append(t)
                    self.__UploadThreadsLock.release()
                    self.__BWControlBoot.set()
                    # start BW control
                    self.__RateAllocBoot.set()
                    # start rate allocation
                    t.start()
                    sleep(PROCESS_TIME)
            else:
                clitcpsock.close(
                )  # close if the number of connections exceeds max
            self.__connectionLock.release()

    # no random coding of the pieces yet. need to modify the function if needed to do so.
    def __convertVideo(self, path, fname):
        FILES = []
        METAS = []
        vidfile = open(fname, 'rb')
        for segNum in range(SEG_PER_CHUNK):
            file = open(path + 'seg' + repr(segNum + 1) + FILE_SUFFIX, 'wb+')
            meta = open(path + 'seg' + repr(segNum + 1) + META_SUFFIX, 'wb+')
            FILES.append(file)
            METAS.append(meta)
            Ind = 0
        data = vidfile.read(BYTES_PER_SEG)
        numofchunks = 0
        numofleftpieces = 0
        while data != "":
            wlen = len(data) * 1.0 / BYTES_PER_PIECE
            if wlen < PIECE_PER_SEG:
                wlen = ceil(wlen)
                data = pack(str(int(wlen * BYTES_PER_PIECE)) + 's', data)
            numofleftpieces += wlen
            FILES[Ind].write(data)
            METAS[Ind].write(
                PIECE_IDS[Ind * PIECE_PER_SEG:Ind * PIECE_PER_SEG + int(wlen)])
            Ind += 1
            Ind = Ind % SEG_PER_CHUNK
            data = vidfile.read(BYTES_PER_SEG)
        vidfile.close()
        numofchunks = int(numofleftpieces / PIECE_PER_CHUNK)
        numofleftpieces = int(numofleftpieces % PIECE_PER_CHUNK)
        if numofleftpieces == 0:
            numofleftpieces = PIECE_PER_CHUNK
        f = open(path + 'length', 'wb+')
        f.write(str(numofchunks) + ',' + str(numofleftpieces))
        f.close()
        for segNum in range(SEG_PER_CHUNK):
            FILES[segNum].close()
            METAS[segNum].close()

    def __userprompt(self, *args):
        while True:
            userinput = raw_input(
                'Input your choice:\n[1] Print Neighbors\n[2] Print Connections\nYour choice>> '
            )
            if userinput == '1':
                self.__printAllNeighbors()
            if userinput == '2':
                self.__printAllConnections()
            else:
                pass

    def __pruneconnections(self, tcpsock, Addr):
        self.__connectionLock.acquire()
        self.__ClientConnectionSocks.remove(tcpsock)
        self.__ClientConnectionIPs.remove(Addr)
        self.__NumofConnections -= 1
        self.__connectionLock.release()

    def __printAllNeighbors(self):
        for eachNeighbor in self.__ClientNeighborhood:
            print eachNeighbor

    def __printAllConnections(self):
        for eachConnectionIP in self.__ClientConnectionIPs:
            print eachConnectionIP
        for eachConnectionSock in self.__ClientConnectionSocks:
            print eachConnectionSock
Ejemplo n.º 19
0
 def __init__(self, cwd, IS_SERVER = 1):
     self.__cwd = cwd                                     # current working directory
     self.__isserver = IS_SERVER                          # I mean the True server, not helper
     self.__tcpSerSock = Mytcpsocket()                    # initiate server socket
     self.__tcpTracSock = Mytcpsocket()                   # initiate tracker socket
     self.__PATH = self.__cwd+os.sep+SERVER_PATH + os.sep # set up video caching directory
     if not os.path.exists(self.__PATH):
             os.makedirs(self.__PATH)
             
     # movieList: vhash: vname; videoDict: vhash: vpath; videoStat: vhash: [NumofChunks, NumofLeftOverPieces]
     self.__movieList = {}; self.__videoDict = {}; self.__videoStat = {};
     # storeAlloc: vhash: vsize; storePrices: vhash: vprice
     self.__storeAlloc = {}; self.__storePrices = {};     
     # mediaReaders: vhash: [a list of open file readers for vhash]; mediaUpdaters: vhash: file writer
     self.__mediaReaders = {}
     self.__mediaUpdaters = {}
     
     if IS_SERVER:
         self.__MaxNumConn = MAX_SERV_CONNECTION
         self.__Addr = MEDIA_SERVER_ADDRESS
         # read all the movies and convert newly added movies
         f = open(self.__PATH+'movielist.txt','r+'); allLines = f.readlines(); f.close();
         for eachmovie in allLines:
             moviename = eachmovie.split('\n')[0]
             self.__movieList[hashlib.md5(moviename).hexdigest()] = moviename         #vhash: vname
         dirList = os.listdir(self.__PATH)
         for dname in dirList:
             if (not os.path.isdir(self.__PATH+dname)) and dname != 'movielist.txt':  # if video not converted, convert
                 hashname = hashlib.md5(dname.split('.')[0]).hexdigest()
                 if (hashname in self.__movieList and not hashname in dirList):
                     videopath = self.__PATH+hashname; os.makedirs(videopath)
                     self.__convertVideo(videopath+os.sep, self.__PATH + dname)       # convert the video
         dirList = os.listdir(self.__PATH)
         for dname in dirList:
             if os.path.isdir(self.__PATH + dname):
                 videopath = self.__PATH + dname + os.sep
                 if dname in self.__movieList:
                     self.__videoDict[dname] = videopath       # vhash: vpath
                     f = open(videopath+'length','rb'); dt= f.readlines();
                     self.__videoStat[dname]=dt[0].split(','); # vhash: [NumofChunks, NumofLeftoverPieces]
                     self.__mediaReaders[dname] = [];
                 else:
                     print videopath                           # not in list, to be deleted
                     shutil.rmtree(videopath)
     else:
         self.__MaxNumConn = MAX_PEER_CONNECTION
         # need to implement NAT traversal
         ##########start here############
         self.__Addr = (([ip for ip in 
                         gethostbyname_ex(gethostname())[2] 
                         if not ip.startswith("127.")][0]), choice(range(50000,60000)))
         ##########end   here############    
         dirList = os.listdir(self.__PATH) 
         for dname in dirList:
             if os.path.isdir(self.__PATH + dname):
                 videopath = self.__PATH + dname + os.sep
                 self.__videoDict[dname] = videopath
                 self.__mediaReaders[dname] = []
                 self.__mediaUpdaters[dname] = MediaFileWrapper(videopath, False) # write access
                 self.__storeAlloc[dname] = 0; self.__storePrices[dname] = 0;
                 
     self.__ClientNeighborhood = []  
     self.__NumofConnections = 0
     self.__ClientConnectionIPs = []
     self.__ClientConnectionSocks = []           
     self.__choketimer = 30
     
     self.__uploadBW = 0                   # KB/sec
     self.__uploadedBytes = 0              # uploaded bytes in a second
     
     self.__UploadThreads = []             # upload threads. used to control UploadBWControl
     
     self.__neighborLock = thread.allocate_lock()
     self.__connectionLock = thread.allocate_lock()
     self.__timerLock = thread.allocate_lock()
     self.__rateAllocLock = thread.allocate_lock()
     self.__mediaReaderLock = thread.allocate_lock()
     self.__uploadStatLock = thread.allocate_lock()
     self.__UploadThreadsLock = thread.allocate_lock()
     self.__BWControlBoot = threading.Event(); self.__BWControlBoot.clear();  # we don't need BW control all the time
     self.__uploadBWExceed = threading.Event(); self.__uploadBWExceed.clear();
     self.__RateAllocBoot = threading.Event(); self.__RateAllocBoot.clear();  # we don't need rate allocation all the time
Ejemplo n.º 20
0
class MediaServer(object):
    '# Author: Hao Zhang\
     # Created: 02/11/2011\
     # Class: MediaServer - a TCP server that uploads data to users'
    def __init__(self, cwd, IS_SERVER = 1):
        self.__cwd = cwd                                     # current working directory
        self.__isserver = IS_SERVER                          # I mean the True server, not helper
        self.__tcpSerSock = Mytcpsocket()                    # initiate server socket
        self.__tcpTracSock = Mytcpsocket()                   # initiate tracker socket
        self.__PATH = self.__cwd+os.sep+SERVER_PATH + os.sep # set up video caching directory
        if not os.path.exists(self.__PATH):
                os.makedirs(self.__PATH)
                
        # movieList: vhash: vname; videoDict: vhash: vpath; videoStat: vhash: [NumofChunks, NumofLeftOverPieces]
        self.__movieList = {}; self.__videoDict = {}; self.__videoStat = {};
        # storeAlloc: vhash: vsize; storePrices: vhash: vprice
        self.__storeAlloc = {}; self.__storePrices = {};     
        # mediaReaders: vhash: [a list of open file readers for vhash]; mediaUpdaters: vhash: file writer
        self.__mediaReaders = {}
        self.__mediaUpdaters = {}
        
        if IS_SERVER:
            self.__MaxNumConn = MAX_SERV_CONNECTION
            self.__Addr = MEDIA_SERVER_ADDRESS
            # read all the movies and convert newly added movies
            f = open(self.__PATH+'movielist.txt','r+'); allLines = f.readlines(); f.close();
            for eachmovie in allLines:
                moviename = eachmovie.split('\n')[0]
                self.__movieList[hashlib.md5(moviename).hexdigest()] = moviename         #vhash: vname
            dirList = os.listdir(self.__PATH)
            for dname in dirList:
                if (not os.path.isdir(self.__PATH+dname)) and dname != 'movielist.txt':  # if video not converted, convert
                    hashname = hashlib.md5(dname.split('.')[0]).hexdigest()
                    if (hashname in self.__movieList and not hashname in dirList):
                        videopath = self.__PATH+hashname; os.makedirs(videopath)
                        self.__convertVideo(videopath+os.sep, self.__PATH + dname)       # convert the video
            dirList = os.listdir(self.__PATH)
            for dname in dirList:
                if os.path.isdir(self.__PATH + dname):
                    videopath = self.__PATH + dname + os.sep
                    if dname in self.__movieList:
                        self.__videoDict[dname] = videopath       # vhash: vpath
                        f = open(videopath+'length','rb'); dt= f.readlines();
                        self.__videoStat[dname]=dt[0].split(','); # vhash: [NumofChunks, NumofLeftoverPieces]
                        self.__mediaReaders[dname] = [];
                    else:
                        print videopath                           # not in list, to be deleted
                        shutil.rmtree(videopath)
        else:
            self.__MaxNumConn = MAX_PEER_CONNECTION
            # need to implement NAT traversal
            ##########start here############
            self.__Addr = (([ip for ip in 
                            gethostbyname_ex(gethostname())[2] 
                            if not ip.startswith("127.")][0]), choice(range(50000,60000)))
            ##########end   here############    
            dirList = os.listdir(self.__PATH) 
            for dname in dirList:
                if os.path.isdir(self.__PATH + dname):
                    videopath = self.__PATH + dname + os.sep
                    self.__videoDict[dname] = videopath
                    self.__mediaReaders[dname] = []
                    self.__mediaUpdaters[dname] = MediaFileWrapper(videopath, False) # write access
                    self.__storeAlloc[dname] = 0; self.__storePrices[dname] = 0;
                    
        self.__ClientNeighborhood = []  
        self.__NumofConnections = 0
        self.__ClientConnectionIPs = []
        self.__ClientConnectionSocks = []           
        self.__choketimer = 30
        
        self.__uploadBW = 0                   # KB/sec
        self.__uploadedBytes = 0              # uploaded bytes in a second
        
        self.__UploadThreads = []             # upload threads. used to control UploadBWControl
        
        self.__neighborLock = thread.allocate_lock()
        self.__connectionLock = thread.allocate_lock()
        self.__timerLock = thread.allocate_lock()
        self.__rateAllocLock = thread.allocate_lock()
        self.__mediaReaderLock = thread.allocate_lock()
        self.__uploadStatLock = thread.allocate_lock()
        self.__UploadThreadsLock = thread.allocate_lock()
        self.__BWControlBoot = threading.Event(); self.__BWControlBoot.clear();  # we don't need BW control all the time
        self.__uploadBWExceed = threading.Event(); self.__uploadBWExceed.clear();
        self.__RateAllocBoot = threading.Event(); self.__RateAllocBoot.clear();  # we don't need rate allocation all the time
            
    def boot(self, uploadBW):
        self.__uploadBW = uploadBW            # force a virtual upload bandwidth; for testing reasons
        if VERBOSE:
            print 'Server %s goes online at %s' % (self.__Addr,ctime())    
        ####### This is fake, just for testing purpose ################
        t = MyThread(self.__uploadBWControl,(1,),self.__uploadBWControl.__name__)
        t.start(); sleep(PROCESS_TIME);
        # rate allocation
        if not self.__isserver:
            t = MyThread(self.__rateallocation,(1,),self.__rateallocation.__name__)
            t.start(); sleep(PROCESS_TIME);
        # register to the tracker
        t = MyThread(self.__commtotracker,(1,),self.__commtotracker.__name__)
        t.start(); sleep(PROCESS_TIME);
        # listen to passive connections
        t = MyThread(self.__WaitforConnection,(1,),self.__WaitforConnection.__name__)
        t.start(); sleep(PROCESS_TIME);
        # actively connect to client
        t = MyThread(self.__Connect2Client,self.__MaxNumConn,self.__Connect2Client.__name__)
        t.start(); sleep(PROCESS_TIME);
        # choking
        t = MyThread(self.__choke,(1,),self.__choke.__name__)
        t.start(); sleep(PROCESS_TIME);
        # user prompt
        t = MyThread(self.__userprompt,(1,),self.__userprompt.__name__) # open a new thread for new requests
        t.start(); sleep(PROCESS_TIME);  
            
    # This is an artificial upload BW control mechanism; only used for debugging purpose
    def __uploadBWControl(self, *targs):
        checkInterval = 0.1
        while True:
            self.__BWControlBoot.wait();                 # wait till there is at least one upload thread running
            self.__uploadStatLock.acquire();
            exceededBytesPerInterval = self.__uploadedBytes - checkInterval*self.__uploadBW
            self.__uploadStatLock.release();
            if exceededBytesPerInterval > 0:
                self.__uploadBWExceed.clear()
                ## fake wait to get more upload BW
                print 'exceeded'
                sleep(exceededBytesPerInterval/self.__uploadBW)
                print 'sleep over'
            # if there does not exist excessive bytes, the uploadBW will expire
            #print self.__uploadedBytes
            self.__uploadStatLock.acquire(); self.__uploadedBytes = 0; self.__uploadStatLock.release();
            self.__uploadBWExceed.set()
            sleep(checkInterval)                         # check every second
            self.__UploadThreadsLock.acquire();
            ThreadstoRemove = []
            for eachThread in self.__UploadThreads:
                if not eachThread.isAlive():
                    ThreadstoRemove.append(eachThread)
            for eachRemoval in ThreadstoRemove:
                self.__UploadThreads.remove(eachRemoval)
            if len(self.__UploadThreads) == 0:
                self.__BWControlBoot.clear()             # if no threads are running, stop uploadBW control thread
            self.__UploadThreadsLock.release();
            
        return
    def __choke(self, *targs):
        while True:
            self.__connectionLock.acquire();
            if self.__NumofConnections >= self.__MaxNumConn:
                ## re-code the choking algorithm by allocating the probabilities##
                ## START ##
                sockind = choice(range(self.__NumofConnections-1))
                ## END ##
                self.__ClientConnectionSocks[sockind].close()
                del self.__ClientConnectionSocks[sockind]
                del self.__ClientConnectionIPs[sockind]
                self.__NumofConnections -= 1
            self.__connectionLock.release();
            if self.__NumofConnections < self.__MaxNumConn:
                self.__Connect2Client(1)             # connect to a new peer
            self.__timerLock.acquire(); sleep(self.__choketimer); self.__timerLock.release();    

    def __upload(self,*targs):
        args = targs[0]; myClisock = args[0]; cliAddr = args[1];
        ack = True; avaPieces = None; ClientFile = None;
        while True:
            self.__BWControlBoot.set(); self.__RateAllocBoot.set();
            data = myClisock.recvmsg(BUFSIZ)
            print data
            if data[0] == 'start':
                videohash = data[1]                          # receive movie hash name
                if not videohash in self.__videoDict.keys(): # this will happen for helpers only. Server needs all videos
                    print self.__videoDict
                    os.makedirs(self.__PATH + videohash)
                    self.__videoDict[videohash] = self.__PATH + videohash + os.sep
                    self.__mediaReaderLock.acquire(); 
                    self.__mediaReaders[videohash] = []; 
                    self.__mediaReaderLock.release();
                    if not self.__isserver:
                        self.__mediaUpdaters[videohash] = MediaFileWrapper(self.__videoDict[videohash],False) # write access
                        self.__rateAllocLock.acquire();
                        self.__storeAlloc[videohash] = 0; self.__storePrices[videohash] = 0;
                        self.__rateAllocLock.release();
                ClientFile = MediaFileWrapper(self.__videoDict[videohash])
                self.__mediaReaders[videohash].append(ClientFile)# add the file reader
                myClisock.sendmsg('ACK')              # send ack
            elif data[0] == 'piece':
                if not self.__isserver:
                    if avaPieces != None:
                        if len(avaPieces) > 0:            # more video than needed
                            self.__rateAllocLock.acquire();
                            self.__storePrices[videohash] -= 1# minus a token
                            print self.__storePrices
                            self.__rateAllocLock.release();
                        else:
                            pass;
                avaPieces = ClientFile.getPieceIdbyChunk(data[1])
                ack = myClisock.sendmsg(avaPieces)
                print avaPieces
            elif data[0] =='content':
                ChunkID,PieceID = data[1],data[2]
                datamsg = ClientFile.getPiecebyId(ChunkID,PieceID)
                if datamsg != None:                   # found the piece
                    ack = myClisock.sendmsg('OK')
                    ## this is a fake constraint on upBW; only for testing purpose
                    self.__uploadBWExceed.wait()      
                    ##############################################################
                    ack = myClisock.sendmsg(datamsg,True)
                    self.__uploadStatLock.acquire();
                    self.__uploadedBytes += BYTES_PER_PIECE
                    self.__uploadStatLock.release();
                    avaPieces = avaPieces.lstrip(PieceID) # remove the piece that is uploaded
                else:
                    ack = myClisock.sendmsg('XX')     # send out a none message
            elif data[0] =='request':
                if not self.__isserver:
                    if avaPieces!= None:
                        if len(avaPieces) == 0:               # could have more video
                            self.__rateAllocLock.acquire();
                            self.__storePrices[videohash] += 1# plus a token
                            print self.__storePrices
                            self.__rateAllocLock.release();
            if not ack or data == 'closed':
                self.__pruneconnections(myClisock, cliAddr)
                if ClientFile != None:
                    ClientFile.closeAll();
                    self.__mediaReaderLock.acquire();
                    self.__mediaReaders[videohash].remove(ClientFile);
                    self.__mediaReaderLock.release();
                break
    
    def __download(self,vhashname,segID,pieceIDs):
        helper = MediaClient(self.__cwd); 
        Success = helper.bootashelper(vhashname, segID, pieceIDs, self.__Addr);
        del helper
        return Success
    
    def __rateallocation(self,*targs):
        while True:
            self.__RateAllocBoot.wait();
            self.__rateAllocLock.acquire();
            if len(self.__storeAlloc) != 0:
                totalsiz = 0
                for vhash in self.__storeAlloc.keys():
                    self.__storeAlloc[vhash] = getFolderSize(self.__videoDict[vhash])
                    totalsiz += self.__storeAlloc[vhash]    # calculate the current total size
                pricevideos = zip(self.__storePrices.values(),self.__storePrices.keys())
                pricevideos.sort(); sortedValues, sortedVideos = zip(*pricevideos) 
                low = 0; high = len(sortedValues)-1;
                self.__rateAllocLock.release();
                while low <= high:
                    if totalsiz < STORAGE_CAP:
                        if sortedValues[high] > 0:
                            totalsiz += self.__storageupdate(sortedVideos[low],totalsiz)  # ++ storage of high
                            high -= 1; continue;
                        else:
                            break;                           # no update because not needed
                    if (abs(sortedValues[low]) < ST_ALLOC_TH # no update because it does not satisfy threshold
                        or abs(sortedValues[high]) < ST_ALLOC_TH):
                        break
                    if self.__mediaUpdaters[sortedVideos[low]].getNumofSeg() <= 0:
                        low += 1; continue;
                    if self.__mediaUpdaters[sortedVideos[high]].getNumofSeg() >= SEG_PER_CHUNK:
                        high -= 1;continue;
                    if sortedValues[low] < 0:
                        totalsiz += self.__storageupdate(sortedVideos[low],totalsiz,False)# -- storage of low
                    if sortedValues[high] > 0:
                        totalsiz += self.__storageupdate(sortedVideos[low],totalsiz);     # ++ storage of high
                self.__rateAllocLock.acquire();
                for vhash in self.__storePrices.keys():
                    self.__storePrices[vhash] = 0            # clear
                #self.__rateAllocLock.release();
            self.__rateAllocLock.release();
            sleep(INTERVAL_RATEALLOC)
            # don't need rate allocation when no download request is present
            self.__UploadThreadsLock.acquire();
            ThreadstoRemove = []
            for eachThread in self.__UploadThreads:
                if not eachThread.isAlive():
                    ThreadstoRemove.append(eachThread)
            for eachRemoval in ThreadstoRemove:
                self.__UploadThreads.remove(eachRemoval)
            if len(self.__UploadThreads) == 0:
                self.__RateAllocBoot.clear()             # if no threads are running, stop rate allocation thread
            self.__UploadThreadsLock.release();
            
    
    # perform the storage add or removal given a video name
    def __storageupdate(self, vhashname, totalsiz, added = True):
        mul = 1
        if added:
            pieceIDs = self.__mediaUpdaters[vhashname].getNewPieceIDs()
            segID = self.__mediaUpdaters[vhashname].getNumofSeg() + 1
            rsize = self.__videoStat[vhashname][0]*BYTES_PER_CHUNK/SEG_PER_CHUNK
            if rsize + totalsiz < STORAGE_CAP:           # write if not exceed storage limit
                if not self.__download(vhashname,segID,pieceIDs):# download data
                    rsize = 0
            else:
                rsize = 0
        else:
            mul = -1
        # the update process is self-locked because the MediaFileWrapper itself is a synchronized process 
        UpdateSuccess = True; 
        self.__mediaReaderLock.acquire();
        for eachClientFile in self.__mediaReaders[vhashname]:
            UpdateSuccess = UpdateSuccess and eachClientFile.UpdateAccess(added)# update file object for each peer
        self.__mediaReaderLock.release();
        self.__mediaUpdaters[vhashname].UpdateAccess(added) # update file access
        if not added and UpdateSuccess:                  # wait for close() before removal
            rsize = self.__mediaUpdaters[vhashname].removeSegment()
        return rsize*mul
    
    def __commtotracker(self, *targs):
        ack = False
        while not ack:
            ack = self.__tcpTracSock.Connect2Server(TRACKER_ADDRESS)
            if ack:
                countdown = 0
                while True:
                    if countdown == 0:
                        ack = self.__tcpTracSock.sendmsg('serv+' + repr(self.__Addr[1]))
                        newneighborhood = self.__tcpTracSock.recvmsg(BUFSIZ)
                        avaiMovieList = self.__tcpTracSock.recvmsg(BUFSIZ)
                        if (not ack) or newneighborhood=='closed' or avaiMovieList == 'closed':
                            ack = False
                            break
                        ACK = 'ACK'
                        if self.__isserver:
                            movienames = ""
                            for fhash, fname in  self.__movieList.iteritems():
                                movienames = (movienames + '+' + fname 
                                              + '#' + self.__videoStat[fhash][0]
                                              + '#' + self.__videoStat[fhash][1])
                            ack = self.__tcpTracSock.sendmsg('list' + movienames)
                            ACK = self.__tcpTracSock.recvmsg(BUFSIZ)
                            if (not ack) or ACK == 'closed':
                                ack = False
                                break
                        else:
                            del self.__videoStat; self.__videoStat = {};
                            for eachmovie in avaiMovieList.keys():
                                self.__videoStat[hashlib.md5(eachmovie).hexdigest()] = avaiMovieList[eachmovie]    
                        self.__neighborLock.acquire()
                        self.__ClientNeighborhood = union(self.__ClientNeighborhood,newneighborhood)
                        ## might have to set a maximum limit of neighborhood ##
                        self.__neighborLock.release()
                        countdown = OBTAIN_NEIGHBOR_PERIOD/INTERVAL_TRACKER_COMMUNICATION
                    else:
                        ack = self.__tcpTracSock.sendmsg('alive')
                        if not ack:
                            break
                        sleep(INTERVAL_TRACKER_COMMUNICATION); countdown -= 1
            sleep(TRY_INTERVAL)
            del self.__tcpTracSock; self.__tcpTracSock = Mytcpsocket();
    
    def __Connect2Client(self, number):
        self.__connectionLock.acquire(); self.__neighborLock.acquire();
        Neighborhood = lminus(self.__ClientNeighborhood, self.__ClientConnectionIPs)
        potentialconnect = sample(Neighborhood, min(len(Neighborhood),number))
        for eachClient in potentialconnect:
            if self.__NumofConnections < self.__MaxNumConn:  
                if eachClient not in self.__ClientConnectionIPs:              
                    cliSock = Mytcpsocket()
                    ack1 = cliSock.Connect2Server(eachClient)
                    ack2 = cliSock.sendmsg(self.__Addr[1])
                    ack3 = cliSock.recvmsg(BUFSIZ)          # receive ACK
                    if ack1 and ack2 and ack3!='closed':
                        self.__NumofConnections += 1
                        self.__ClientConnectionSocks.append(cliSock);
                        self.__ClientConnectionIPs.append(eachClient);
                        t = MyThread(self.__upload,(cliSock,eachClient),self.__upload.__name__)
                        self.__UploadThreadsLock.acquire(); self.__UploadThreads.append(t); self.__UploadThreadsLock.release()
                        self.__BWControlBoot.set();               # start BW control
                        self.__RateAllocBoot.set();               # start rate allocation
                        t.start(); sleep(PROCESS_TIME);
                    else:
                        self.__ClientNeighborhood.remove(eachClient)
            else:
                break;
        self.__connectionLock.release(); self.__neighborLock.release();
            
    def __WaitforConnection(self, *targs):
        self.__tcpSerSock.InitServSock(self.__Addr,self.__MaxNumConn)
        if VERBOSE:
            print "Waiting for connection..."
        while True:            
            (tcpClientSock, CLIENT_ADDR) = self.__tcpSerSock.WaitforConn()
            self.__connectionLock.acquire();
            clitcpsock = Mytcpsocket(tcpClientSock)
            if self.__NumofConnections < self.__MaxNumConn:
                servport = clitcpsock.recvmsg(BUFSIZ)
                ack = clitcpsock.sendmsg('ACK')
                CLIENT_SERV_ADDR = (CLIENT_ADDR[0],servport)
                if ((CLIENT_SERV_ADDR in self.__ClientConnectionIPs) 
                    or (not ack) or servport == 'closed'):
                    clitcpsock.close()
                else:
                    self.__ClientConnectionSocks.append(clitcpsock);
                    self.__ClientConnectionIPs.append(CLIENT_SERV_ADDR);
                    self.__NumofConnections += 1;
                    if VERBOSE:
                        print "...connected from:", CLIENT_ADDR
                    t = MyThread(self.__upload,(clitcpsock,CLIENT_SERV_ADDR),self.__upload.__name__)
                    self.__UploadThreadsLock.acquire(); self.__UploadThreads.append(t); self.__UploadThreadsLock.release()
                    self.__BWControlBoot.set();               # start BW control
                    self.__RateAllocBoot.set();               # start rate allocation
                    t.start(); sleep(PROCESS_TIME);
            else:
                clitcpsock.close()          # close if the number of connections exceeds max
            self.__connectionLock.release();
            
    # no random coding of the pieces yet. need to modify the function if needed to do so.
    def __convertVideo(self,path,fname):
        FILES = [];
        METAS = [];
        vidfile = open(fname,'rb')
        for segNum in range(SEG_PER_CHUNK):
            file = open(path+'seg'+repr(segNum+1)+FILE_SUFFIX,'wb+')
            meta = open(path+'seg'+repr(segNum+1)+META_SUFFIX,'wb+')
            FILES.append(file); METAS.append(meta)
            Ind = 0
        data = vidfile.read(BYTES_PER_SEG)
        numofchunks = 0; numofleftpieces = 0;
        while data!="":
            wlen = len(data)*1.0/BYTES_PER_PIECE
            if wlen < PIECE_PER_SEG:
                wlen = ceil(wlen)
                data = pack(str(int(wlen*BYTES_PER_PIECE))+'s',data)
            numofleftpieces += wlen
            FILES[Ind].write(data)
            METAS[Ind].write(PIECE_IDS[Ind*PIECE_PER_SEG:Ind*PIECE_PER_SEG+int(wlen)])
            Ind += 1; Ind = Ind%SEG_PER_CHUNK;
            data = vidfile.read(BYTES_PER_SEG)
        vidfile.close()
        numofchunks = int(numofleftpieces/PIECE_PER_CHUNK)
        numofleftpieces = int(numofleftpieces%PIECE_PER_CHUNK)
        if numofleftpieces ==0:
            numofleftpieces = PIECE_PER_CHUNK
        f = open(path+'length','wb+'); f.write(str(numofchunks)+','+str(numofleftpieces));
        f.close();
        for segNum in range(SEG_PER_CHUNK):
            FILES[segNum].close();
            METAS[segNum].close();
            
    def __userprompt(self, *args):
        while True:
            userinput = raw_input('Input your choice:\n[1] Print Neighbors\n[2] Print Connections\nYour choice>> ')
            if userinput == '1':
                self.__printAllNeighbors()
            if userinput == '2':
                self.__printAllConnections()
            else:
                pass;
    
    def __pruneconnections(self,tcpsock,Addr):
        self.__connectionLock.acquire();
        self.__ClientConnectionSocks.remove(tcpsock)
        self.__ClientConnectionIPs.remove(Addr)
        self.__NumofConnections -= 1
        self.__connectionLock.release();
        
    def __printAllNeighbors(self):
        for eachNeighbor in self.__ClientNeighborhood:
            print eachNeighbor

    def __printAllConnections(self):
        for eachConnectionIP in self.__ClientConnectionIPs:
            print eachConnectionIP
        for eachConnectionSock in self.__ClientConnectionSocks:
            print eachConnectionSock
Ejemplo n.º 21
0
class Tracker(object):
    def __init__(self, Tracker_Addr = TRACKER_ADDRESS):
        self.__socket = Mytcpsocket()                  # a new socket
        self.__Addr = Tracker_Addr                     # IP address + port
        self.__MaxNumConn = MAX_TRAC_CONNECTION        
        self.__userDict = {}                           # connecting addresses of active (estimate) users
        self.__servDict = {}                           # connecting addresses of active (estimate) helpers
        #self.__servDict[MEDIA_SERVER_ADDRESS] = 1      # the central server
        self.__inputLock = thread.allocate_lock()      # lock for the input variables
        self.__EXIT = 0                                # exit the system or not
        self.__movieList = {}                          # list of movie names
   
    def __userprompt(self, *args):
        while True:
            userinput = raw_input('Input your choice:\n[0] Print All Movies\n[1] Print Registered Peers\n[2] Disconnect\nYour choice>> ')
            if userinput =='0':
                self.__printAllMovies()
            elif userinput == '1':
                self.__printAllregistered()
            elif userinput == '2':
                self.__inputLock.acquire(); self.__EXIT = 1; self.__inputLock.release();
                break;
            else:
                pass;
    
    def boot(self):
        t = MyThread(self.__userprompt,(1,),self.__userprompt.__name__) # open a new thread for new requests
        t.start(); sleep(PROCESS_TIME);
        
        self.__socket.InitServSock(self.__Addr,self.__MaxNumConn)             
        while True:
            (tcpCliSock, CIENT_ADDR) = self.__socket.WaitforConn()            
            t = MyThread(self.__registerpeer,(tcpCliSock,CIENT_ADDR),
                         self.__registerpeer.__name__) # open a new thread for new requests
            #self.__threads.append(t)         
            t.start(); sleep(PROCESS_TIME)             # allow process time for the thread
            self.__inputLock.acquire() 
            if self.__EXIT == 1:
                self.__socket.close(); 
                break;
            self.__inputLock.release()

    def __registerpeer(self,*targs):                    # register the peer and obtain a list of potential neighbors
        args = targs[0]
        CliSocket = args[0]; CliAddr = args[1];
        myClisock = Mytcpsocket(CliSocket)  
        IS_SERV = -1      
        while True:
            data = myClisock.recvmsg(BUFSIZ)
            if 'serv' in str.lower(data):
                IS_SERV = 1;
                CliAddr = (CliAddr[0],int(data.split('+')[1]))
                self.__servDict[CliAddr] = 1
                pc = self.__potentialconn(CliAddr, self.__userDict) # return a list of user addresses \ itself
                myClisock.sendmsg(pc)
                myClisock.sendmsg(self.__movieList)                 # send movie list to watch
            elif 'user' in str.lower(data):
                IS_SERV = 0;
                CliAddr = (CliAddr[0],int(data.split('+')[1]))
                self.__userDict[CliAddr] = 1
                pc = self.__potentialconn(CliAddr, self.__servDict) # return a list of serv addresses \ itself
                myClisock.sendmsg(pc)
                myClisock.sendmsg(self.__movieList)                 # send movie list to watch
            elif 'list' in str.lower(data):
                data = data.split('+')
                for i in range(1,len(data)):
                    videostat = data[i].split('#'); 
                    self.__movieList[videostat[0]] = [int(videostat[1]),int(videostat[2])]
                myClisock.sendmsg('ACK')
            elif str.lower(data) == 'alive':                        # still alive
                print data, ' from ', CliAddr 
                pass;
            else:
                if IS_SERV == 1:
                    self.__servDict.pop(CliAddr)
                elif IS_SERV == 0:
                    self.__userDict.pop(CliAddr)                             
                myClisock.close()                                           # close the connection
                break
            
            
    def __potentialconn(self, CliAddr, PotentialConnections):
        'return a list of potential connections -- list of IP/ports in the other Dictionary set-minus itself'
        def notself(query):
            return (CliAddr != query);
        return filter(notself,sample(PotentialConnections, 
                                     min(len(PotentialConnections),NUM_RETURNED_PEERS)))
    def __printAllregistered(self):
        print 'Registered users:'
        for eachUsr in self.__userDict:
            print eachUsr
        print '\nRegistered servers:'
        for eachServ in self.__servDict:
            print eachServ
     
    def __printAllMovies(self):
        for i, eachmovie in enumerate(self.__movieList):
            print repr(i+1)+'. ' + eachmovie   
Ejemplo n.º 22
0
 def __registerpeer(self,*targs):                    # register the peer and obtain a list of potential neighbors
     args = targs[0]
     CliSocket = args[0]; CliAddr = args[1];
     myClisock = Mytcpsocket(CliSocket)  
     IS_SERV = -1      
     while True:
         data = myClisock.recvmsg(BUFSIZ)
         if 'serv' in str.lower(data):
             IS_SERV = 1;
             CliAddr = (CliAddr[0],int(data.split('+')[1]))
             self.__servDict[CliAddr] = 1
             pc = self.__potentialconn(CliAddr, self.__userDict) # return a list of user addresses \ itself
             myClisock.sendmsg(pc)
             myClisock.sendmsg(self.__movieList)                 # send movie list to watch
         elif 'user' in str.lower(data):
             IS_SERV = 0;
             CliAddr = (CliAddr[0],int(data.split('+')[1]))
             self.__userDict[CliAddr] = 1
             pc = self.__potentialconn(CliAddr, self.__servDict) # return a list of serv addresses \ itself
             myClisock.sendmsg(pc)
             myClisock.sendmsg(self.__movieList)                 # send movie list to watch
         elif 'list' in str.lower(data):
             data = data.split('+')
             for i in range(1,len(data)):
                 videostat = data[i].split('#'); 
                 self.__movieList[videostat[0]] = [int(videostat[1]),int(videostat[2])]
             myClisock.sendmsg('ACK')
         elif str.lower(data) == 'alive':                        # still alive
             print data, ' from ', CliAddr 
             pass;
         else:
             if IS_SERV == 1:
                 self.__servDict.pop(CliAddr)
             elif IS_SERV == 0:
                 self.__userDict.pop(CliAddr)                             
             myClisock.close()                                           # close the connection
             break
Ejemplo n.º 23
0
 def __registerpeer(
         self, *targs
 ):  # register the peer and obtain a list of potential neighbors
     args = targs[0]
     CliSocket = args[0]
     CliAddr = args[1]
     myClisock = Mytcpsocket(CliSocket)
     IS_SERV = -1
     while True:
         data = myClisock.recvmsg(BUFSIZ)
         if 'serv' in str.lower(data):
             IS_SERV = 1
             CliAddr = (CliAddr[0], int(data.split('+')[1]))
             self.__servDict[CliAddr] = 1
             pc = self.__potentialconn(
                 CliAddr, self.__userDict
             )  # return a list of user addresses \ itself
             myClisock.sendmsg(pc)
             myClisock.sendmsg(self.__movieList)  # send movie list to watch
         elif 'user' in str.lower(data):
             IS_SERV = 0
             CliAddr = (CliAddr[0], int(data.split('+')[1]))
             self.__userDict[CliAddr] = 1
             pc = self.__potentialconn(
                 CliAddr, self.__servDict
             )  # return a list of serv addresses \ itself
             myClisock.sendmsg(pc)
             myClisock.sendmsg(self.__movieList)  # send movie list to watch
         elif 'list' in str.lower(data):
             data = data.split('+')
             for i in range(1, len(data)):
                 videostat = data[i].split('#')
                 self.__movieList[videostat[0]] = [
                     int(videostat[1]),
                     int(videostat[2])
                 ]
             myClisock.sendmsg('ACK')
         elif str.lower(data) == 'alive':  # still alive
             print data, ' from ', CliAddr
             pass
         else:
             if IS_SERV == 1:
                 self.__servDict.pop(CliAddr)
             elif IS_SERV == 0:
                 self.__userDict.pop(CliAddr)
             myClisock.close()  # close the connection
             break
Ejemplo n.º 24
0
    def __init__(self, cwd, IS_SERVER=1):
        self.__cwd = cwd  # current working directory
        self.__isserver = IS_SERVER  # I mean the True server, not helper
        self.__tcpSerSock = Mytcpsocket()  # initiate server socket
        self.__tcpTracSock = Mytcpsocket()  # initiate tracker socket
        self.__PATH = self.__cwd + os.sep + SERVER_PATH + os.sep  # set up video caching directory
        if not os.path.exists(self.__PATH):
            os.makedirs(self.__PATH)

        # movieList: vhash: vname; videoDict: vhash: vpath; videoStat: vhash: [NumofChunks, NumofLeftOverPieces]
        self.__movieList = {}
        self.__videoDict = {}
        self.__videoStat = {}
        # storeAlloc: vhash: vsize; storePrices: vhash: vprice
        self.__storeAlloc = {}
        self.__storePrices = {}
        # mediaReaders: vhash: [a list of open file readers for vhash]; mediaUpdaters: vhash: file writer
        self.__mediaReaders = {}
        self.__mediaUpdaters = {}

        if IS_SERVER:
            self.__MaxNumConn = MAX_SERV_CONNECTION
            self.__Addr = MEDIA_SERVER_ADDRESS
            # read all the movies and convert newly added movies
            f = open(self.__PATH + 'movielist.txt', 'r+')
            allLines = f.readlines()
            f.close()
            for eachmovie in allLines:
                moviename = eachmovie.split('\n')[0]
                self.__movieList[hashlib.md5(
                    moviename).hexdigest()] = moviename  #vhash: vname
            dirList = os.listdir(self.__PATH)
            for dname in dirList:
                if (
                        not os.path.isdir(self.__PATH + dname)
                ) and dname != 'movielist.txt':  # if video not converted, convert
                    hashname = hashlib.md5(dname.split('.')[0]).hexdigest()
                    if (hashname in self.__movieList
                            and not hashname in dirList):
                        videopath = self.__PATH + hashname
                        os.makedirs(videopath)
                        self.__convertVideo(videopath + os.sep, self.__PATH +
                                            dname)  # convert the video
            dirList = os.listdir(self.__PATH)
            for dname in dirList:
                if os.path.isdir(self.__PATH + dname):
                    videopath = self.__PATH + dname + os.sep
                    if dname in self.__movieList:
                        self.__videoDict[dname] = videopath  # vhash: vpath
                        f = open(videopath + 'length', 'rb')
                        dt = f.readlines()
                        self.__videoStat[dname] = dt[0].split(',')
                        # vhash: [NumofChunks, NumofLeftoverPieces]
                        self.__mediaReaders[dname] = []
                    else:
                        print videopath  # not in list, to be deleted
                        shutil.rmtree(videopath)
        else:
            self.__MaxNumConn = MAX_PEER_CONNECTION
            # need to implement NAT traversal
            ##########start here############
            self.__Addr = (([
                ip for ip in gethostbyname_ex(gethostname())[2]
                if not ip.startswith("127.")
            ][0]), choice(range(50000, 60000)))
            ##########end   here############
            dirList = os.listdir(self.__PATH)
            for dname in dirList:
                if os.path.isdir(self.__PATH + dname):
                    videopath = self.__PATH + dname + os.sep
                    self.__videoDict[dname] = videopath
                    self.__mediaReaders[dname] = []
                    self.__mediaUpdaters[dname] = MediaFileWrapper(
                        videopath, False)  # write access
                    self.__storeAlloc[dname] = 0
                    self.__storePrices[dname] = 0

        self.__ClientNeighborhood = []
        self.__NumofConnections = 0
        self.__ClientConnectionIPs = []
        self.__ClientConnectionSocks = []
        self.__choketimer = 30

        self.__uploadBW = 0  # KB/sec
        self.__uploadedBytes = 0  # uploaded bytes in a second

        self.__UploadThreads = [
        ]  # upload threads. used to control UploadBWControl

        self.__neighborLock = thread.allocate_lock()
        self.__connectionLock = thread.allocate_lock()
        self.__timerLock = thread.allocate_lock()
        self.__rateAllocLock = thread.allocate_lock()
        self.__mediaReaderLock = thread.allocate_lock()
        self.__uploadStatLock = thread.allocate_lock()
        self.__UploadThreadsLock = thread.allocate_lock()
        self.__BWControlBoot = threading.Event()
        self.__BWControlBoot.clear()
        # we don't need BW control all the time
        self.__uploadBWExceed = threading.Event()
        self.__uploadBWExceed.clear()
        self.__RateAllocBoot = threading.Event()
        self.__RateAllocBoot.clear()
Ejemplo n.º 25
0
class Tracker(object):
    def __init__(self, Tracker_Addr=TRACKER_ADDRESS):
        self.__socket = Mytcpsocket()  # a new socket
        self.__Addr = Tracker_Addr  # IP address + port
        self.__MaxNumConn = MAX_TRAC_CONNECTION
        self.__userDict = {}  # connecting addresses of active (estimate) users
        self.__servDict = {
        }  # connecting addresses of active (estimate) helpers
        #self.__servDict[MEDIA_SERVER_ADDRESS] = 1      # the central server
        self.__inputLock = thread.allocate_lock(
        )  # lock for the input variables
        self.__EXIT = 0  # exit the system or not
        self.__movieList = {}  # list of movie names

    def __userprompt(self, *args):
        while True:
            userinput = raw_input(
                'Input your choice:\n[0] Print All Movies\n[1] Print Registered Peers\n[2] Disconnect\nYour choice>> '
            )
            if userinput == '0':
                self.__printAllMovies()
            elif userinput == '1':
                self.__printAllregistered()
            elif userinput == '2':
                self.__inputLock.acquire()
                self.__EXIT = 1
                self.__inputLock.release()
                break
            else:
                pass

    def boot(self):
        t = MyThread(
            self.__userprompt, (1, ),
            self.__userprompt.__name__)  # open a new thread for new requests
        t.start()
        sleep(PROCESS_TIME)

        self.__socket.InitServSock(self.__Addr, self.__MaxNumConn)
        while True:
            (tcpCliSock, CIENT_ADDR) = self.__socket.WaitforConn()
            t = MyThread(self.__registerpeer, (tcpCliSock, CIENT_ADDR),
                         self.__registerpeer.__name__
                         )  # open a new thread for new requests
            #self.__threads.append(t)
            t.start()
            sleep(PROCESS_TIME)  # allow process time for the thread
            self.__inputLock.acquire()
            if self.__EXIT == 1:
                self.__socket.close()
                break
            self.__inputLock.release()

    def __registerpeer(
            self, *targs
    ):  # register the peer and obtain a list of potential neighbors
        args = targs[0]
        CliSocket = args[0]
        CliAddr = args[1]
        myClisock = Mytcpsocket(CliSocket)
        IS_SERV = -1
        while True:
            data = myClisock.recvmsg(BUFSIZ)
            if 'serv' in str.lower(data):
                IS_SERV = 1
                CliAddr = (CliAddr[0], int(data.split('+')[1]))
                self.__servDict[CliAddr] = 1
                pc = self.__potentialconn(
                    CliAddr, self.__userDict
                )  # return a list of user addresses \ itself
                myClisock.sendmsg(pc)
                myClisock.sendmsg(self.__movieList)  # send movie list to watch
            elif 'user' in str.lower(data):
                IS_SERV = 0
                CliAddr = (CliAddr[0], int(data.split('+')[1]))
                self.__userDict[CliAddr] = 1
                pc = self.__potentialconn(
                    CliAddr, self.__servDict
                )  # return a list of serv addresses \ itself
                myClisock.sendmsg(pc)
                myClisock.sendmsg(self.__movieList)  # send movie list to watch
            elif 'list' in str.lower(data):
                data = data.split('+')
                for i in range(1, len(data)):
                    videostat = data[i].split('#')
                    self.__movieList[videostat[0]] = [
                        int(videostat[1]),
                        int(videostat[2])
                    ]
                myClisock.sendmsg('ACK')
            elif str.lower(data) == 'alive':  # still alive
                print data, ' from ', CliAddr
                pass
            else:
                if IS_SERV == 1:
                    self.__servDict.pop(CliAddr)
                elif IS_SERV == 0:
                    self.__userDict.pop(CliAddr)
                myClisock.close()  # close the connection
                break

    def __potentialconn(self, CliAddr, PotentialConnections):
        'return a list of potential connections -- list of IP/ports in the other Dictionary set-minus itself'

        def notself(query):
            return (CliAddr != query)

        return filter(
            notself,
            sample(PotentialConnections,
                   min(len(PotentialConnections), NUM_RETURNED_PEERS)))

    def __printAllregistered(self):
        print 'Registered users:'
        for eachUsr in self.__userDict:
            print eachUsr
        print '\nRegistered servers:'
        for eachServ in self.__servDict:
            print eachServ

    def __printAllMovies(self):
        for i, eachmovie in enumerate(self.__movieList):
            print repr(i + 1) + '. ' + eachmovie
Ejemplo n.º 26
0
class MediaClient(object):
    '# Author: Hao Zhang\
     # Created: 02/11/2011\
     # Class: MediaClient - a TCP client  that downloads data from the servers'
    # Initialization -- set up address and port; initilize parameters
    def __init__(self,cwd):
        self.__cwd = cwd                                  # current working directory
        self.__BootedasUser = True
        self.__tcpTracSock = Mytcpsocket()
        self.__tcpListenSock = Mytcpsocket()
        self.__MaxNumConn = MAX_PEER_CONNECTION
        self.__Addr = (([ip for ip in 
                            gethostbyname_ex(gethostname())[2] 
                            if not ip.startswith("127.")][0]), choice(range(50000,60000)))
        
        self.__tcpCliSockets = []           
        self.__ServerNeighborhood = []
        self.__ServerConnectionIPs = []
        self.__ServerConnectionSocks = []           
        self.__NumofConnections = 0
        self.__ExcludedServerAddr = []
        self.__choketimer = 30
        self.__StartWaiting = False
        
        self.__receivedFile = None                        # streaming file object
        self.__avaiMovieList = {}                         # available movie list from the tracker
        self.__movieHashNames = {}
        self.__currentvid = 'None'                        # current video that is being watched
        self.__NumofChunks = 0
        self.__NumofLeftPieces = 0
        
        self.__neighborLock = thread.allocate_lock()      # lock for the neighborhood update
        self.__connectionLock = thread.allocate_lock()
        self.__timerLock = thread.allocate_lock()
        self.__streamingStatLock = thread.allocate_lock()
        self.__bufferStatLock = thread.allocate_lock()
        self.__emptyAvailable = threading.Event(); self.__emptyAvailable.clear();  # one of the download chunks is waiting for other corresponding threads to finish that chunk
        self.__DownloadWait = threading.Event(); self.__DownloadWait.clear();      # wait till download is finished
        self.__BufferFullWait = threading.Event(); self.__BufferFullWait.clear();  # buffer too much, wait before download
        self.__BufferEmptyWait = threading.Event(); self.__BufferEmptyWait.clear();# buffer not enough, download from server
        self.__streamingWait = threading.Event(); self.__streamingWait.clear();    # wait till buffer is ready to stream
        self.__downloadthreads = []
        self.__EXIT = False
        
    # Boot as a pure user with prompt
    def bootasuser(self):
        self.__streamingPath = self.__cwd + os.sep + CLIENT_PATH + os.sep
        if not os.path.exists(self.__streamingPath):
            os.makedirs(self.__streamingPath)
        self.__PiecestoDownload = PIECE_IDS       # as a user, download all the pieces
        self.__PiecesperChunk = PIECE_PER_CHUNK
        if VERBOSE:
            print 'User %s goes online at %s' % (self.__Addr,ctime())
        # register to the tracker
        t = MyThread(self.__commtotracker,(1,),self.__commtotracker.__name__)
        t.start(); sleep(PROCESS_TIME);
        # choking
        t = MyThread(self.__choke,(1,),self.__choke.__name__)
        t.start(); sleep(PROCESS_TIME);
        # enable user prompt
        t = MyThread(self.__userprompt,(1,),self.__userprompt.__name__) # open a new thread for new requests
        t.start(); sleep(PROCESS_TIME);  
    
    # Boot as a downloader to get packets (as a helper)
    def bootashelper(self, videohash, segID, piecestodownload, excludedServerAddr):
        self.__BootedasUser = False
        self.__ExcludedServerAddr = excludedServerAddr
        self.__PiecestoDownload = piecestodownload # as a helper, specify pieces to download
        self.__PiecesperChunk = len(piecestodownload)
        self.__streamingPath = self.__cwd + os.sep + SERVER_PATH + os.sep + videohash + os.sep + 'seg' + str(segID) + FILE_SUFFIX
        self.__MetaPath = self.__cwd + os.sep + SERVER_PATH + os.sep + videohash + os.sep + 'seg' + str(segID) + META_SUFFIX
        self.__BufferFullWait.set() # no need to buffer download for helper 
        #### need a mechanism to control this: need to be either too greedy or too conservative
        self.__BufferEmptyWait.set()
        ######
        
        # register to the tracker
        t = MyThread(self.__commtotracker,(1,),self.__commtotracker.__name__)
        t.start(); sleep(PROCESS_TIME*2);
        # choking
        t = MyThread(self.__choke,(1,),self.__choke.__name__)
        t.start(); sleep(PROCESS_TIME);
        # enable download
        self.__movieInitialize(videohash); sleep(PROCESS_TIME);
        self.__DownloadWait.wait();        # wait until download is finished
        self.__EXIT = True
        return True
        
    def __bufferControl(self, *targs):
        while True:
            if self.__EXIT:
                return
            self.__streamingStatLock.acquire();
            if self.__streamedNumofChunks >= self.__NumofChunks:
                print self.__NumofChunks, self.__streamedNumofChunks;
                self.__streamingWait.set();                                     # let the stream break
                self.__streamingStatLock.release();
                break
            if self.__streamingBufferLength < 1:                                # less than a second of buffer to play
                self.__streamingWait.clear()                                    # stop streaming
                self.__BufferEmptyWait.set(); self.__BufferFullWait.set();      # start downloading NOW!
            else:
                self.__streamingWait.set()                                      # let it stream
                if self.__streamingBufferLength >= BUFFER_TOO_MUCH:             # buffer too much
                    self.__BufferFullWait.clear();self.__BufferEmptyWait.clear()# stop downloading
                elif self.__streamingBufferLength >= BUFFER_LENGTH:
                    self.__BufferEmptyWait.clear()
                elif self.__streamingBufferLength < BUFFER_LENGTH:              # buffer less than required length
                    self.__BufferFullWait.set()                                 # download from helpers
                    if self.__streamingBufferLength < BUFFER_EMERG_LEFT:        # if less than emergency
                        self.__BufferEmptyWait.set()                            # download from the SERVER
                    else:
                        self.__BufferEmptyWait.clear()
            self.__streamingStatLock.release();
            sleep(BUFFER_CHECK_INTERVAL)

    def __streaming(self, *targs):
        speedup = 1
        while True:
            if self.__EXIT:
                return
            self.__streamingWait.wait()
            ### stream the video NOW for duration xxx ###
            ### Now it is Fake streaming ###
            sleep(1)
            self.__streamingStatLock.acquire()
            if self.__streamingBufferLength > 1:
                self.__streamingBufferLength -= speedup
                print 'subtracted, BufferLength = ', self.__streamingBufferLength
                self.__streamedNumofChunks += speedup*self.__streamingRate/BYTES_PER_CHUNK
            if self.__streamedNumofChunks >= self.__NumofChunks:
                print self.__NumofChunks, self.__streamedNumofChunks;
                self.__streamingStatLock.release();
                break
            self.__streamingStatLock.release()
            ################################
    
    def __choke(self, *targs):
        while True:
            if self.__EXIT:
                return
            self.__connectionLock.acquire();
            if self.__NumofConnections >= self.__MaxNumConn:
                ## re-code the choking algorithm by allocating the probabilities##
                ## START ##
                sockind = choice(range(self.__NumofConnections-1))
                ## END ##
                self.__ServerConnectionSocks[sockind].close()
                del self.__ServerConnectionSocks[sockind]
                del self.__ServerConnectionIPs[sockind]
                self.__NumofConnections -= 1
            self.__connectionLock.release();
            if self.__NumofConnections < self.__MaxNumConn and self.__currentvid != 'None':
                self.__Connect2Server((1,self.__currentvid))             # connect to a new peer
            self.__timerLock.acquire(); sleep(self.__choketimer); self.__timerLock.release();
            
    def __download(self,*targs):
        args = targs[0]; servSock = args[0]; servAddr = args[1]; videohash = args[2];
        self.__DownloadWait.clear();
        while True:
            if videohash == 'None':
                servSock.sendmsg('closed')
                self.__pruneconnections(servSock, servAddr)
                self.__DownloadWait.set();
                return
            ack = servSock.sendmsg(['start',videohash])  # send which video to watch
            ACK = servSock.recvmsg(BUFSIZ)               # receive acknowledgement
            if not ack or ACK == 'closed':
                self.__pruneconnections(servSock, servAddr)
                self.__DownloadWait.set();
                return
            currentChunkID = -1; piecesperchunk = self.__PiecesperChunk;
            while True:
                if self.__EXIT:
                    return
                if servAddr == MEDIA_SERVER_ADDRESS: # wait until buffer is too little
                    self.__BufferEmptyWait.wait()
                else:                                # wait until buffer is less than a certain threshold
                    self.__BufferFullWait.wait()
                self.__bufferStatLock.acquire();
                if videohash != self.__currentvid:
                    videohash = self.__currentvid
                    self.__bufferStatLock.release();
                    break 
                if currentChunkID < self.__bufferheadChunkID:
                    currentChunkID = self.__bufferheadChunkID
                    self.__bufferStatLock.release();
                    ack = servSock.sendmsg(['piece',currentChunkID])
                    #print ack
                    avaiPieceIDsfromServ = servSock.recvmsg(BUFSIZ)
                    #print avaiPieceIDsfromServ
                    if not ack or avaiPieceIDsfromServ == 'closed':
                        self.__pruneconnections(servSock, servAddr)
                        self.__DownloadWait.set();
                        return
                    continue
                avaiPieceIDsfromServ = intersect(avaiPieceIDsfromServ,self.__avaiPieceIDs)# Now I am sure no other peers are giving me the same data 
                RequestingSet = lminus(avaiPieceIDsfromServ,self.__PiecesNowRequested)
                #print RequestingSet, "from", servAddr
                if len(RequestingSet) == 0:
                    if len(lminus(self.__avaiPieceIDs,self.__PiecesNowRequested)) > 0:
                        ack = servSock.sendmsg(['request'])
                        if not ack:
                            self.__pruneconnections(servSock, servAddr)
                            self.__bufferStatLock.release(); self.__DownloadWait.set();
                            return
                    self.__bufferStatLock.release();
                    self.__emptyAvailable.wait(BUFFER_EMERG_LEFT)    # wait until this chunk is over
                    continue
                PiecesToRequest = choice(RequestingSet)              # randomly choose an available piece
                self.__PiecesNowRequested.extend(PiecesToRequest)    # put it into the requesting queue
                self.__bufferStatLock.release();
                ack = servSock.sendmsg(['content',currentChunkID,PiecesToRequest])# download the piece
                ACK = servSock.recvmsg(BUFSIZ)
                if ACK == 'OK':
                    data = servSock.recvmsg(BYTES_PER_PIECE,True)     # only receive if server still has it
                else:                                                 # if ACK == 'XX'
                    avaiPieceIDsfromServ.remove(PiecesToRequest)      # otherwise remove it and continue
                    self.__PiecesNowRequested = lminus(self.__PiecesNowRequested, PiecesToRequest)
                    continue
                #print data[0:5]
                print "data from server", servAddr
                self.__bufferStatLock.acquire();
                if videohash != self.__currentvid:                    # if no longer watching current video, leave
                    videohash = self.__currentvid
                    self.__bufferStatLock.release();
                    break 
                if not ack or data == 'closed':                       # check if the connection is still alive
                    self.__pruneconnections(servSock, servAddr)
                    self.__PiecesNowRequested = lminus(self.__PiecesNowRequested, PiecesToRequest)
                    self.__bufferStatLock.release();      
                    self.__DownloadWait.set();
                    return
                if currentChunkID < self.__bufferheadChunkID:         # if other processes have already advanced the chunk, then dump it
                    self.__bufferStatLock.release();
                    continue
                # finally I made sure the downloaded pieces is valid and needed
                self.__PiecesNowRequested = lminus(self.__PiecesNowRequested,PiecesToRequest) # change status requested to available
                self.__avaiPieceIDs = lminus(self.__avaiPieceIDs, PiecesToRequest)
                self.__bufferPieceIDs.extend(PiecesToRequest)
                self.__bufferContent.append(data)
                if len(self.__bufferPieceIDs) >= piecesperchunk:      # finished downloading of a chunk
                    sortedIDs, self.__bufferContent = PacketsDecode(self.__bufferContent,self.__bufferPieceIDs)
                    if self.__BootedasUser:
                        ##### feed the buffer to the streaming wrapper #####
                        ##### now just write the file #####
                        self.__receivedFile.write(self.__bufferContent)
                        ##### END #########################
                    else:
                        self.__MetaFile.write(sortedIDs)
                        self.__receivedFile.write(self.__bufferContent)
                    self.__streamingStatLock.acquire();              # change streaming buffer length in seconds
                    self.__streamingBufferLength += piecesperchunk*BYTES_PER_PIECE/self.__streamingRate
                    print 'added, BufferLength = ', self.__streamingBufferLength
                    self.__streamingStatLock.release();    
                    self.__bufferPieceIDs = []; self.__bufferContent = [];
                    self.__PiecesNowRequested = []; self.__avaiPieceIDs = self.__PiecestoDownload;
                    piecesperchunk = self.__PiecesperChunk; self.__bufferheadChunkID += 1;
                    if self.__bufferheadChunkID == self.__NumofChunks:
                        self.__avaiPieceIDs = intersect(PIECE_IDS[0:self.__NumofLeftPieces], self.__PiecestoDownload) # last chunk left pieces
                        piecesperchunk = len(self.__avaiPieceIDs)
                    if self.__bufferheadChunkID > self.__NumofChunks or piecesperchunk == 0:
                        self.__currentvid = 'None'                   # finish download
                        self.__NumofChunks = 0
                        self.__receivedFile.close()
                        if not self.__BootedasUser:
                            self.__MetaFile.close()
                        self.__DownloadWait.set();                   # set the wait to finish
                    self.__emptyAvailable.set();                     # release the available ID empty lock
                    self.__emptyAvailable.clear();                   # set the lock again for next round
                self.__bufferStatLock.release();
    
    def __movieInitialize(self, videohash):    
        ## dump all current                                # dump the current streaming if possible
        self.__bufferStatLock.acquire();
        if self.__currentvid == videohash:
                self.__bufferStatLock.release();
                return
        #### movie paramter initialization:
        self.__streamingRate = BYTES_PER_CHUNK/BUFFER_LENGTH
        self.__streamingBufferLength = 0                # in units of seconds
        self.__streamedNumofChunks = 0                  # number of chunks that are streamed
        self.__bufferheadChunkID = 0                    # the chunk ID in front of the buffer
        self.__bufferContent = []                       # integer IDs
        self.__bufferPieceIDs = []                      # string names
        self.__PiecesNowRequested = []                  # pieces that are now requested
        self.__avaiPieceIDs = self.__PiecestoDownload   # initialize available pieces to watch
        self.__streamingWait.clear(); self.__BufferFullWait.clear(); self.__BufferEmptyWait.clear();
        if videohash != 'None':                             # if a movie was requested
            self.__NumofChunks = self.__movieHashNames[videohash][0]
            self.__NumofLeftPieces = self.__movieHashNames[videohash][1]
            self.__currentvid = videohash
            if self.__receivedFile != None:                 # close the opened file
                self.__receivedFile.close()
            if self.__BootedasUser:
                writeFilePath = self.__streamingPath + videohash + '.flv'
                #writeFilePath = self.__streamingPath + 'hancock-tsr2_h480p' + '.flv'
            else:
                writeFilePath = self.__streamingPath
                self.__MetaFile = open(self.__MetaPath,'w+b')
            self.__receivedFile=open(writeFilePath,'w+b')   # open a writable file
            if self.__BootedasUser:
                t = MyThread(self.__bufferControl,(1,),self.__bufferControl.__name__);
                t.start(); sleep(PROCESS_TIME);                                 # start buffer control
                t = MyThread(self.__streaming,(1,),self.__streaming.__name__);  # start streaming
                t.start(); sleep(PROCESS_TIME);
            else:
                self.__BufferEmptyWait.set(); self.__BufferFullWait.set();
            t = MyThread(self.__Connect2Server,(self.__MaxNumConn,videohash),self.__Connect2Server.__name__);
            t.start(); sleep(PROCESS_TIME);
            if self.__StartWaiting == False:                # listen to active server to user connections
                self.__StartWaiting = True
                t = MyThread(self.__WaitforConnection,(1,),self.__WaitforConnection.__name__);
                t.start(); sleep(PROCESS_TIME);     
        else:
            self.__NumofChunks = 0
            self.__NumofLeftPieces = 0
            self.__currentvid = 'None'                      # not watching any videos
        self.__bufferStatLock.release();
    
    def __commtotracker(self, *targs):
        ack = False
        while not ack:
            if self.__EXIT:
                return
            ack = self.__tcpTracSock.Connect2Server(TRACKER_ADDRESS)
            #print TRACKER_ADDRESS
            if ack:
                countdown = 0
                while True:
                    if self.__EXIT:
                        return
                    if countdown == 0:
                        ack = self.__tcpTracSock.sendmsg('user+' + repr(self.__Addr[1]))
                        newneighborhood = self.__tcpTracSock.recvmsg(BUFSIZ)
                        self.__avaiMovieList = self.__tcpTracSock.recvmsg(BUFSIZ)
                        if (not ack) or newneighborhood =='closed' or self.__avaiMovieList == 'closed':
                            ack = False
                            break 
                        del self.__movieHashNames; self.__movieHashNames = {};
                        for eachmovie in self.__avaiMovieList.keys():
                            self.__movieHashNames[hashlib.md5(eachmovie).hexdigest()] = self.__avaiMovieList[eachmovie]
                        self.__neighborLock.acquire()
                        ## might have to set a maximum limit of neighborhood ##
                        self.__ServerNeighborhood = union(self.__ServerNeighborhood,newneighborhood)
                        self.__ServerNeighborhood = lminus(self.__ServerNeighborhood,self.__ExcludedServerAddr)
                        self.__neighborLock.release()
                        countdown = OBTAIN_NEIGHBOR_PERIOD/INTERVAL_TRACKER_COMMUNICATION
                    else:
                        ack = self.__tcpTracSock.sendmsg('alive')
                        if not ack:
                            break
                        sleep(INTERVAL_TRACKER_COMMUNICATION); countdown -= 1; # send alive msg interval 
            sleep(TRY_INTERVAL)       # obtain neighborhood/movielist interval
            del self.__tcpTracSock; self.__tcpTracSock = Mytcpsocket();
                    
    def __WaitforConnection(self, *targs):
        self.__tcpListenSock.InitServSock(self.__Addr,self.__MaxNumConn)
        while True:     
            if self.__EXIT:
                return       
            (tcpServSock, SERVER_ADDR) = self.__tcpListenSock.WaitforConn()
            self.__connectionLock.acquire();
            servtcpsock = Mytcpsocket(tcpServSock)
            if self.__NumofConnections < self.__MaxNumConn:
                servport = servtcpsock.recvmsg(BUFSIZ)
                ack = servtcpsock.sendmsg('ACK')                    # send ACK
                SERVER_SERV_ADDR = (SERVER_ADDR[0],servport)
                if ((SERVER_SERV_ADDR in self.__ServerConnectionIPs) or 
                    (SERVER_SERV_ADDR == self.__ExcludedServerAddr) or 
                    (not ack) or servport == 'closed'):
                    servtcpsock.close()
                else:
                    self.__ServerConnectionSocks.append(servtcpsock)
                    self.__ServerConnectionIPs.append(SERVER_SERV_ADDR)
                    self.__NumofConnections += 1
                    if VERBOSE:
                        print "...connected from:", SERVER_SERV_ADDR
                    t = MyThread(self.__download,
                                 (servtcpsock,SERVER_SERV_ADDR,self.__currentvid),self.__download.__name__)
                    t.start(); sleep(PROCESS_TIME);
                    self.__downloadthreads.append(t)
            else:
                servtcpsock.close()                                # close if the number of connections exceeds max
            self.__connectionLock.release();
            
    def __Connect2Server(self, *targs):
        args = targs[0]; number = args[0]; videohash = args[1];
        self.__connectionLock.acquire(); self.__neighborLock.acquire();
        Neighborhood = lminus(self.__ServerNeighborhood, self.__ServerConnectionIPs)
        potentialconnect = sample(Neighborhood, min(len(Neighborhood),number))
        for eachServer in potentialconnect:
            if self.__NumofConnections < self.__MaxNumConn:     
                if eachServer not in self.__ServerConnectionIPs:           
                    servSock = Mytcpsocket()
                    ack1 = servSock.Connect2Server(eachServer)
                    ack2 = servSock.sendmsg(self.__Addr[1])
                    ack3 = servSock.recvmsg(BUFSIZ)          # receive ACK
                    if ack1 and ack2 and ack3!='closed':
                        self.__NumofConnections += 1
                        self.__ServerConnectionSocks.append(servSock)
                        self.__ServerConnectionIPs.append(eachServer)
                        t = MyThread(self.__download,(servSock,eachServer,videohash),
                                     self.__download.__name__)
                        t.start(); sleep(PROCESS_TIME);
                        self.__downloadthreads.append(t);
                    else:
                        self.__ServerNeighborhood.remove(eachServer)
            else:
                break
        self.__connectionLock.release(); self.__neighborLock.release();
    
    def __userprompt(self, *args):
        while True:
            if self.__EXIT:
                return
            userinput = raw_input('<<<Select a function>>>:\n[-1] Exit\n[1] Watch a Movie\n[2] Print Neighbors\n[3] Print Connections\nYour choice>> ')
            if userinput == '1':
                numofmovies = len(self.__avaiMovieList)
                if numofmovies == 0:
                    print 'No movies to watch yet!'
                    continue
                print '<<<Select a movie>>>:'
                print '#. <<Go back>>'
                print '0. <<Stop the current movie>>'
                for i,fname in enumerate(self.__avaiMovieList):
                    print  repr(i+1)+'. '+fname
                input = raw_input('Your choice>> ')                   
                if input == '#':                                   # if the user wants to go back
                    pass;
                elif input >= '0' and input <= str(numofmovies):   
                    movieID = int(input)-1 
                    if movieID >=0:                                # watch a movie
                        for i, eachmovie in enumerate(self.__avaiMovieList):
                            if i == movieID:
                                videohash = hashlib.md5(eachmovie).hexdigest()
                                break;
                    else:
                        videohash = 'None'                         # stop watching the current movie
                    self.__movieInitialize(videohash)              # initialize movie download and watching
            elif userinput == '2':
                self.__printAllNeighbors()
            elif userinput == '3':
                self.__printAllConnections()
            elif userinput =='-1':
                self.__EXIT = True
                return;
            else:
                pass;    

    def __pruneconnections(self,tcpsock,Addr):
        self.__connectionLock.acquire();
        print tcpsock, Addr
        print self.__ServerConnectionSocks
        self.__ServerConnectionSocks.remove(tcpsock)
        self.__ServerConnectionIPs.remove(Addr)
        self.__NumofConnections -= 1
        self.__connectionLock.release();
    
    def __closeAllconnections(self):
        self.__connectionLock.acquire();
        for connection in self.__ServerConnectionSocks:
            connection.close()
        self.__ServerConnectionSocks = []
        self.__ServerConnectionIPs = []
        self.__NumofConnections = 0
        self.__connectionLock.release();
        
    def __printAllNeighbors(self):
        for eachNeighbor in self.__ServerNeighborhood:
            print eachNeighbor

    def __printAllConnections(self):
        for eachConnectionIP in self.__ServerConnectionIPs:
            print eachConnectionIP
        for eachConnectionSock in self.__ServerConnectionSocks:
            print eachConnectionSock