Beispiel #1
0
    def run(self):
        SIZE = 65000
        while True:
            #TODO: what if not all the data comes at once?
            data, address = self.sock.recvfrom(SIZE)
            if address[0] == self.ip and address[1] == self.ignore_port:
                continue
            query = ZapTorrentProtocolParser(data)
            zap_debug_print("in zap_broadcast and got some data! ", data)
            zap_debug_print("address is", address)
            zap_debug_print("my ignoring stuff is", self.ip, self.ignore_port)
            query.parse()
            if query.message_type == 'error':
                self.sock.sendto(query.response, address)
            elif query.message_type == 'files?':

                #BUILD LIST OF FILES AND SEND BACK
                response = ZapTorrentProtocolResponse(response_type='files', name=ZapConfig.name,
                                                      ip=self.ip,
                                                      port=ZapConfig.tcp_port)
                for filename in self.local_files.get_files():
                    f = self.local_files.get_files()[filename][0]
                    zap_debug_print("Adding a local file, and it is", f)
                    response.add(f)
                zap_debug_print("response is ", response.as_response())
                self.sock.sendto(response.as_response(), address)
Beispiel #2
0
 def download_block(self, filename, id, ip, port):
     query = ZapTorrentProtocolResponse(response_type='download?',
         filename=filename, id=id, name=ZapConfig.name,
         ip=ZapConfig.ip, port=ZapConfig.tcp_port)
     msg = query.as_response()
     sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
     sock.connect((ip, int(port)))
     self.send_to_socket(sock, msg)
     resp = sock.recv(54000)
     zap_debug_print("download_blocks got %s back" % resp)
     #TODO: what if we don't receive the
     # entire first chunk, or we get an error?
     if len(resp) == 0:
         raise RuntimeError("socket closed remotely!")
     parser = ZapTorrentProtocolParser(resp)
     parser.parse()
     if parser.message_type == 'download':
         #make sure we have the whole block
         while len(parser.fields['data']) < int(parser.fields['bytes']):
             parser.fields['data'] += sock.recv(54000)
         sock.close()
         return parser.fields['data']
     else:
         zap_debug_print("Error downloading a block: got ", resp)
         sock.close()
         return None
Beispiel #3
0
    def get_blocks(self, **kwargs):
        if 'status' in kwargs:
            for block in self.blocks:
                zap_debug_print(dir(block))

            return filter(lambda x: x.status == kwargs['status'], self.blocks)
        else:
            return self.blocks
Beispiel #4
0
    def run(self):
        self.print_welcome()

        self.discoverer.start()
        #Send something to the discover sock so we can bind it to a port
        self.discoverer.sock.sendto("HURP DURP", ("<broadcast>", self.broadcast_port))
        own_address = self.discoverer.sock.getsockname()
        zap_debug_print("my udp discovery port is", own_address[1])
        ignore_port = own_address[1]
        b = ZapBroadcast(self.broadcast_port, self.local_files,
                self.remote_files, self.ip, ignore_port)
        b.start()

        tcp_server = ZapTCPServer(port=self.tcp_port, host=self.ip, local_files=self.local_files)
        tcp_server.start()

        while True:
            line = raw_input(self.prompt + " ")
            if re.match('^quit$', line):
                self.quit()
            elif re.match('^name (\w+)$', line):
                ZapConfig.name = re.match(r"^name (\w+)$", line).group(1)
                print("Name is now %s" % ZapConfig.name)
            elif re.match('^list$', line):
                self.remote_files.clear()
                query = ZapTorrentProtocolResponse(response_type="files?").as_response()
                s = self.discoverer.sock
                length = 0
                while length < len(query):
                    sent_length = s.sendto(query, ("<broadcast>", self.broadcast_port))
                    length += sent_length
                #now wait for the filesLister to get more info
                print("Waiting for response from peers. . .")
                time.sleep(3)
                for k in self.remote_files.get_files():
                    print("File: %s" % k)
            elif re.match('^load ([\w\._\-/]+)$', line):
                path = re.match('^load ([\w\._\-/]+)$', line).group(1)
                f = ZapFile()
                if f.set_path(path):
                    zap_debug_print("Loaded a local file and it is ", f)
                    self.local_files.add(f)
                    print("File at %s loaded for sharing." % path)
                else:
                    print("File at %s doesn't exist, or it is a directory. Try a different path." % path)
            elif re.match('^get ([\w\.\-]+)$', line):
                filename =  re.match('^get ([\w\.\-]+)$', line).group(1)
                remote_files = self.remote_files.get(filename)
                if remote_files is not None:
                    downloader = ZapDownloader(remote_files, self.local_files)
                    downloader.start()
                    print("Starting to download %s." % filename)
                else:
                    print("No files by that name. Sorry. Try 'list' to update your list of files.")

            else:
                self.print_usage()
                continue
Beispiel #5
0
 def __init__(self, port, verbose):
     self.prompt = "[Zap Torrent]"
     self.port = port
     self.local_files = ZapFiles()
     self.remote_files = ZapFiles()
     ZapConfig.verbose = verbose
     self.ip = self.get_ip()
     zap_debug_print("my ip is %s, port is %d" % (self.ip, self.port))
     self.broadcast_port = port
     ZapConfig.ip = self.get_ip()
     self.discoverer = FilesLister(port=self.broadcast_port, remote_files=self.remote_files)
     ZapConfig.tcp_port = random.randint(1300, 40000)
     self.tcp_port = ZapConfig.tcp_port
Beispiel #6
0
    def run(self):
        """Spawn off threads to download each block. When all
        threads return, check if the file is completely
        downloaded. If so, determine its digest and make
        sure it matches, and save it to disk."""
        start_time = time.time()
        file_info = self.remote_files[0]
        remote_file = ZapFile()
        remote_file.filename = file_info.filename
        remote_file.number_of_blocks = file_info.number_of_blocks
        remote_file.mark_as_remote()
        self.local_files.add(remote_file)
        child_threads = []

        for f in self.remote_files:
            remote_location = {}
            remote_location['ip'] = f.ip
            remote_location['port'] = f.port
            remote_location['name'] = f.name
            child_thread = self.remote_file_downloader(remote_file, f)
            child_thread.start()
            child_threads.append(child_thread)

        # How do we wait for them to finish?
        # TODO: what if I can't download the whole file?
        while not remote_file.is_downloaded():
            time.sleep(4)

        # Now all child threads are gone, I hope.
        remote_file.save_to_disk()
        zap_debug_print("remote file digest is ", remote_file.digest, "file_info.digest is ", file_info.digest)
        if remote_file.digest != file_info.digest:
            # Our file does not match. Quit this thread and return an error
            zap_debug_print("Digest does not match! I should delete downloaded file!")
            self.local_files.remove(remote_file)
            os.remove(remote_file.path)
            return False
        else:
            stop_time = time.time()
            log_string = "file %s %s %s" % (remote_file.filename, os.path.getsize(remote_file.path),
                    stop_time - start_time)
            zap_log(log_string)
            print("Finished downloading %s. Find it at %s." % (remote_file.filename, remote_file.path))
            return True
Beispiel #7
0
 def get_ip(self):
     sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
     ip = ""
     try:
         sock.connect(("google.com", 80))
         ip = sock.getsockname()[0]
     except socket.gaierror:
         # if there is no connection to the internet, try getting it by just
         # broadcasting
         sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
         try:
             sock.sendto("HURP DURP", ("<broadcast>", self.port))
             zap_debug_print("self.port is %d" % self.port)
             ip = sock.getsockname()[0]
         except socket.error:
             print >> sys.stderr, ("Sorry, but I can't connect to the network for some reason.")
             print >> sys.stderr, ("Check your network connection and try running ZapTorrent again.")
             sys.exit(2)
     return ip
Beispiel #8
0
    def as_response(self):
        """Format the response as a ZapTorrent protocol response and
        return it as a string."""
        # <b>Response</b>
        # ZT 1.0 files [name] [IP] [port] [number]\n
        # [filename] [digest] [blocks]\n
        # [filename] [digest] [blocks]\n
        # ...
        response_string = self.string
        if self.response_type == "files":
            # add the four fields
            response_string += " %s %s %d %d\n" % (self.fields['name'],
                    self.fields['ip'], self.fields['port'], len(self.stuff_to_add))
            zap_debug_print("in as_response before for loop, and constructed following response: %s" % response_string)
            for f in self.stuff_to_add:
                response_string += "%s %s %d\n" % (f.filename, f.digest, f.number_of_blocks)
            zap_debug_print("in as_response, and constructed following response: %s" % response_string)
        elif self.response_type == "files?":
            response_string += "\n"
        # <b>Message</b>
        # ZT 1.0 inventory? [filename]\n

        # <b>Response</b>
        # ZT 1.0 inventory [filename] [blocks]\n
        # [id] [bytes]\n
        # [id] [bytes]\n
        # ...
        elif self.response_type == 'inventory?':
            response_string += " %s\n" % self.fields['filename']
        elif self.response_type == 'inventory':
            response_string += " %s %d\n" % (self.fields['filename'], self.fields['blocks'])
            for f in self.stuff_to_add:
                response_string += "%d %d\n" % (f.id, f.size)
        # <b>Message</b>
        # ZT 1.0 download? [filename] [id] [name] [IP] [port]\n

        # <b>Response</b>
        # ZT 1.0 download [filename] [id] [bytes]\n
        # ...
        elif self.response_type == 'download?':
            response_string += " %s %s %s %s %s\n" % (self.fields['filename'],
                    self.fields['id'], self.fields['name'], self.fields['ip'],
                    self.fields['port'])
        elif self.response_type == 'download':
            number_of_bytes = len(self.fields['bytes'])
            zap_debug_print("Fields are", self.fields['filename'], self.fields['id'],
                    number_of_bytes, self.fields['bytes'])
            response_string += " %s %d %d\n" % (self.fields['filename'], int(self.fields['id']),
                    number_of_bytes)
            response_string += self.fields['bytes']
        return response_string
Beispiel #9
0
    def run(self):
        #TODO: what if we don't receive it all at once?
        msg = self.sock.recv(54000)
        zap_debug_print("Got a message on the ZAPTCPResponseThread and it is", msg)
        response = ""
        query = ZapTorrentProtocolParser(msg)
        query.parse()
        if query.message_type == 'error':
            response = query.response
        elif query.message_type == 'inventory?':
            #Look for the file in local_files
            f = self.local_files.get(query.fields['filename'])
            if f is None:
                response = "ZT 1.0 error No file named %s" % query.fields['filename']
            else:
                f = f[0]
                r = ZapTorrentProtocolResponse(response_type="inventory", filename=f.filename, blocks=f.number_of_blocks)
                r.stuff_to_add = f.get_blocks(status='present')
                zap_debug_print("got back some blocks and they looks like this:", r.stuff_to_add)
                response = r.as_response()
        elif query.message_type == 'download?':
            #make sure we have the file
            f = self.local_files.get(query.fields['filename'])
            if f is None:
                response = "ZT 1.0 error No file named %s" % query.fields['filename']
            else:
                f = f[0]
                if f.block_is_present(int(query.fields['id'])):
                    r = ZapTorrentProtocolResponse(response_type="download", filename=f.filename, id=query.fields['id'],
                            bytes=f.get_block(int(query.fields['id'])).get_bytes())
                    response = r.as_response()
                    log_string = "upload %s %s %s %s %s %s" % (f.filename, ZapConfig.name,
                            query.fields['ip'], query.fields['port'], query.fields['id'],
                            len(f.get_block(int(query.fields['id'])).get_bytes()))
                    zap_log(log_string)
                else:
                    response = "ZT 1.0 error No block for %s at %s\n" % (f.filename, query.fields['id'])

        else:
            response = "ZT 1.0 error unknown TCP query type.\n"
        sent_length = 0
        zap_debug_print("sending %s as response" % response)
        while sent_length < len(response):
            message_remaining = response[sent_length:]
            length = self.sock.send(message_remaining)
            sent_length += length
        #TODO: do I close it on my end?
        self.sock.close()
Beispiel #10
0
 def run(self):
     # In a loop - aquire the lock
     # Check if the peer info has any stuff that I don't have
     # If so, mark it as downloading and release the lock
     # download it
     # Aquire the lock again
     # Mark the downloaded block as present
     # Release the lock
     while True:
         # We get the blocks each time in case the peer
         # has since received new blocks
         blocks_available = self.get_available_blocks(self.peer_info.ip,
                 self.peer_info.port, self.peer_info.filename)
         zap_debug_print("Blocks available are ", blocks_available)
         self.remote_file.sem.acquire()
         block_to_download = None
         for block_id in blocks_available:
             if self.remote_file.does_block_needs_downloading(int(block_id)):
                 block_to_download = int(block_id)
                 self.remote_file.mark_block_as('downloading', int(block_to_download))
                 break
         self.remote_file.sem.release()
         if block_to_download is None:
             zap_debug_print("No more blocks to download from" +
                     " this peer: ", self.peer_info)
             break
         data = self.download_block(self.peer_info.filename,
                 block_to_download, self.peer_info.ip,
                 self.peer_info.port)
         zap_debug_print("received %s back from the download query" % data)
         if data is not None:
             self.remote_file.set_block_data(block_to_download, data)
             self.remote_file.mark_block_as('present', block_to_download)
             log_string = "download %s %s %s %s %s %s" % (self.peer_info.filename,
                     self.peer_info.name, self.peer_info.ip, self.peer_info.port,
                     block_to_download, len(data))
             zap_log(log_string)
         else:
             # Mark the block to be downloaded again.
             print(("error downloading block %s from" % block_to_download), self.peer_info)
             self.remote_file.mark_block_as('not-present', int(block_to_download))
Beispiel #11
0
 def run(self):
     size = 55000
     while True:
         data, address = self.sock.recvfrom(size)
         #ignore stuff sent from our own socket
         if address[0] == ZapConfig.ip and address[1] == self.ignore_port:
             continue
         query = ZapTorrentProtocolParser(data)
         zap_debug_print("Got some data! ", data)
         zap_debug_print("my address is", (ZapConfig.ip, self.port))
         zap_debug_print("other address is", address)
         zap_debug_print("about to parse the query in FilesLister")
         query.parse()
         if query.message_type == "files":
             # Parse the files out of the query, and store them in the remote files
             zap_debug_print("got a files reponse: ", data)
             ip = query.get_field('ip')
             port = query.get_field('port')
             name = query.get_field('name')
             for f in query.get_files():
                 zf = ZapFile(status="not-present")
                 zf.ip = ip
                 zf.port = port
                 zf.name = name
                 zf.number_of_blocks = f['blocks']
                 zf.digest = f['digest']
                 zf.filename = f['filename']
                 zap_debug_print("Someone told me about a file named", zf.filename)
                 self.remote_files.add(zf)
Beispiel #12
0
    def parse(self):
        if self.protocol_matchers['files?'].match(self.data):
            self.message_type = "files?"
        elif self.protocol_matchers['files'].match(self.data):
            match = self.protocol_matchers['files'].match(self.data)
            self.message_type = 'files'
            self.fields['ip'] = match.group('ip')
            self.fields['name'] = match.group('name')
            self.fields['port'] = match.group('port')
            self.files_list = []
            num_files = match.group('num_files')
            file_list = match.group('rest')
            filename_re = re.compile(r"^(?P<filename>[\w\.\-]+) (?P<digest>[\w]+) (?P<blocks>\d+)$")
            # splitting on new lines when the string ends with a newline results in
            # an empty string. Check for empty string when looking.
            for line_number, line in enumerate(file_list.split("\n")):
                # parse the file fields
                file_line_match = filename_re.match(line)
                if file_line_match is None or line_number + 1 > num_files:
                    if line == "":
                        continue
                    else:
                        self.message_type = 'error'
                        self.response = "ZT 1.0 error File lines not correctly formatted.\n"
                self.files_list.append({ 'filename': file_line_match.group('filename'),
                    'digest': file_line_match.group('digest'), 'blocks': file_line_match.group('blocks')})
        elif self.protocol_matchers['inventory?'].match(self.data):
            match = self.protocol_matchers['inventory?'].match(self.data)
            self.message_type = 'inventory?'
            self.fields['filename'] = match.group('filename')
        elif self.protocol_matchers['inventory'].match(self.data):
            match =  self.protocol_matchers['inventory'].match(self.data)
            self.message_type = 'inventory'
            self.fields['filename'] = match.group('filename')
            self.fields['blocks'] = match.group('blocks')

            self.block_list = []
            block_list = match.group('rest')
            zap_debug_print("protocol blocks look like this: %s" % block_list)
            block_line_re = re.compile(r"^(?P<id>\d+) (?P<bytes>\d+)$")
            for line_number, line in enumerate(block_list.split('\n')):
                block_line_match = block_line_re.match(line)
                if block_line_match is None or line_number + 1 > self.fields['blocks']:
                    if block_line_match == "":
                        continue
                    else:
                        self.message_type = "error"
                        self.response = "ZT 1.0 error Block lines not correctly formatted.\n"
                        break
                else:
                    self.block_list.append({ 'id':
                        block_line_match.group('id'), 'bytes':
                        block_line_match.group('bytes')})

        elif self.protocol_matchers['download?'].match(self.data):
            match = self.protocol_matchers['download?'].match(self.data)
            self.message_type = 'download?'
            self.fields['filename'] = match.group('filename')
            self.fields['id'] = match.group('id')
            self.fields['name'] = match.group('name')
            self.fields['ip'] = match.group('ip')
            self.fields['port'] = match.group('port')
        elif self.protocol_matchers['download'].match(self.data):
            match = self.protocol_matchers['download'].match(self.data)
            self.message_type = 'download'
            self.fields['filename'] = match.group('filename')
            self.fields['id'] = match.group('id')
            self.fields['bytes'] = match.group('bytes')
            self.fields['data'] = match.group('data')
        else:
            zap_debug_print("Nothing matched", self.data)
            self.message_type = "error"
            self.response = "ZT 1.0 error Could not recognize protocol.\n"