def failureResponse(failure_reason=None, failure_code=None, interval=None): response = {} if not failure_reason: failure_reason = 'Invalid Request' if not interval: interval = settings.ANNOUNCE_INTERVAL_INVALIDREQUEST response['failure reason'] = failure_reason if failure_code: response['failure code'] = failure_code response['interval'] = interval return HttpResponse(bencode(response))
def announce(request): # Parse a query string given as a string argument. try: qs = manual_GET(request) except: return(failureResponse(failure_reason='Invalid request type: client request was not a HTTP GET.', failure_code=100)) # Create dict to collect the response parts. response_dict = {} # Check if there is an info_hash if qs.get('info_hash') is None: return(failureResponse(failure_reason='Missing info_hash.', failure_code=101)) # get info_hash info_hash = qs.get('info_hash') # encode info_hash try: info_hash = urllib.unquote_plus(info_hash) info_hash = info_hash.encode('hex') except: # TODO: search correct exception return(failureResponse(failure_reason='Invalid info_hash')) # Check if there is a Torrent with this info_hash. try: torrent = Torrent.objects.get(info_hash=info_hash) except Torrent.DoesNotExist: # Torrent does not exist, so return failure reason. return(failureResponse(failure_reason='Torrent not found', failure_code=200, interval=settings.ANNOUNCE_INTERVAL_NOTFOUND)) # Check Request try: port = request.GET['port'] event = request.GET.get('event', '') peer_id = request.GET.get('peer_id') ip = request.META.get('REMOTE_ADDR') # nginx workaround if ip == '127.0.0.1': ip = request.META.get('HTTP_X_REAL_IP') except MultiValueDictKeyError: # The request is invalid, so return failure reason. return(failureResponse()) announce_method_options = ['compact', 'no_peer_id'] announce_method_results = {} for key in announce_method_options: if not request.GET.get(key): announce_method_results[key] = False else: announce_method_results[key] = request.GET.get(key) try: announce_method_results[key] = int(announce_method_results[key]) except ValueError: # if string is not convertable to integer, set the given method to false announce_method_results[key] = False if announce_method_results[key] == 1: announce_method_results[key] = True else: # if given method is a integer and if it's not 1, the given method is invalid! # to prevent of sending a failure response, set the given method to false # this means, that the tracker sends a standard response to the client announce_method_results[key] = False # Process eventstate if 'started' in event: peer, created = Peer.objects.get_or_create(peer_id=peer_id, port=port, ip=ip, torrent=torrent) if created: peer.save() elif 'stopped' in event: try: peer = Peer.objects.get(peer_id=peer_id, ip=ip, torrent=torrent) peer.delete() except Peer.DoesNotExist: pass elif 'completed' in event or '' in event: pass # Implement numwant - specifies how many peers the actual peer wants in his peerlist numwant = request.GET.get('numwant', settings.NUM_WANT) try: numwant = int(numwant) except TypeError: numwant = settings.NUM_WANT # Add existing peers, and interval to response_dict exist_peers = [] peers = Peer.objects.filter(torrent=torrent) peers[:numwant] if announce_method_results['compact'] == True: print('DEBUG: compact response') exist_peers = "" for peer in peers: exist_peers += pack('>4sH', inet_aton(peer.ip), peer.port) elif announce_method_results['no_peer_id'] == True: print('DEBUG: no_peer_id response') exist_peers = [] for peer in peers: exist_peers.append({'ip': peer.ip, 'port': peer.port}) else: print('DEBUG: standard response') exist_peers = [] for peer in peers: exist_peers.append({'peer id': peer.peer_id, 'ip': peer.ip, 'port': peer.port}) response_dict['peers'] = exist_peers response_dict['interval'] = randomInterval() # Return bencoded response. return HttpResponse(bencode(response_dict))