<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def FetchRequestsAndResponses(self, session_id, timestamp=None):
 """Fetches all outstanding requests and responses for this flow. We first cache all requests and responses for this flow in memory to prevent round trips. Args: session_id: The session_id to get the requests/responses for. timestamp: Tuple (start, end) with a time range. Fetched requests and responses will have timestamp in this range. Yields: an tuple (request protobufs, list of responses messages) in ascending order of request ids. Raises: MoreDataException: When there is more data available than read by the limited query. """

    if timestamp is None:
      timestamp = (0, self.frozen_timestamp or rdfvalue.RDFDatetime.Now())

    num_requests = 0
    for request, responses in self.data_store.ReadRequestsAndResponses(
        session_id,
        timestamp=timestamp,
        request_limit=self.request_limit,
        response_limit=self.response_limit):
      yield (request, responses)
      num_requests += 1

    if num_requests >= self.request_limit:
      raise MoreDataException()