private void process(Request request, Response response,
			OutputStream body) throws IOException {
		/* Parse the query parameters.
		 *
		 * Unfortunately we need to rely on our own parsing function here
		 * because SimpleHTTP's Query map will contain UTF-8 decoded
		 * parameters, which doesn't work well for the byte-encoded strings we
		 * expect.
		 */
		Map<String, String> params = this.parseQuery(
				request.getAddress().toString());

		// Prepare the response headers.
		response.set("Content-Type", "text/plain");
		response.set("Server", this.version);
		response.setDate("Date", System.currentTimeMillis());

		// TODO:
		//	change to add torrent if error == TrackerError.UNKNOWN_TORRENT
		// Validate the announce request coming from the client.
		TrackerError error = this.validateAnnounceRequest(params);
		if (error != null) {
			this.serveError(response, body, Status.BAD_REQUEST, error);
			return;
		}

		// Make sure we have the peer IP, fallbacking on the request's source
		// address if the peer didn't provide it.
		if (!params.containsKey("ip")) {
			params.put("ip", request.getClientAddress().getAddress()
					.getHostAddress());
		}

		// Grab the corresponding torrent (validateAnnounceRequest already made
		// sure we knew about this Torrent)
		TrackedTorrent torrent = this.torrents.get(params.get("info_hash_hex"));
		if (torrent == null) {
			this.serveError(response, body, Status.INTERNAL_SERVER_ERROR,
					TrackerError.UNKNOWN_TORRENT);
			return;
		}

		ByteBuffer peerId = ByteBuffer.wrap(params.get("peer_id")
				.getBytes(TrackedTorrent.BYTE_ENCODING));
		// Update the torrent according to the announce event
		TrackedPeer peer = torrent.update(params.get("event"),
				peerId, params.get("peer_id_hex"),
				params.get("ip"), Integer.parseInt(params.get("port")),
				Long.parseLong(params.get("uploaded")),
				Long.parseLong(params.get("downloaded")),
				Long.parseLong(params.get("left"))
				);

		// Craft and output the answer
		BEncoder.bencode(torrent.peerAnswerAsBEValue(peer), body);
	}