예제 #1
0
static void continue_send_message(grpc_exec_ctx *exec_ctx,
                                  grpc_call_element *elem) {
  call_data *calld = elem->call_data;
  while (grpc_byte_stream_next(
      exec_ctx, calld->send_op->payload->send_message.send_message, ~(size_t)0,
      &calld->got_slice)) {
    grpc_byte_stream_pull(exec_ctx,
                          calld->send_op->payload->send_message.send_message,
                          &calld->incoming_slice);
    grpc_slice_buffer_add(&calld->slices, calld->incoming_slice);
    if (calld->send_length == calld->slices.length) {
      finish_send_message(exec_ctx, elem);
      break;
    }
  }
}
예제 #2
0
static void got_slice(grpc_exec_ctx *exec_ctx, void *elemp, grpc_error *error) {
  grpc_call_element *elem = elemp;
  call_data *calld = elem->call_data;
  if (GRPC_ERROR_NONE !=
      grpc_byte_stream_pull(exec_ctx,
                            calld->send_op->payload->send_message.send_message,
                            &calld->incoming_slice)) {
    /* Should never reach here */
    abort();
  }
  grpc_slice_buffer_add(&calld->slices, calld->incoming_slice);
  if (calld->send_length == calld->slices.length) {
    finish_send_message(exec_ctx, elem);
  } else {
    continue_send_message(exec_ctx, elem);
  }
}
예제 #3
0
static void perform_stream_op(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
                              grpc_stream *gs,
                              grpc_transport_stream_op_batch *op) {
  INPROC_LOG(GPR_DEBUG, "perform_stream_op %p %p %p", gt, gs, op);
  inproc_stream *s = (inproc_stream *)gs;
  gpr_mu *mu = &s->t->mu->mu;  // save aside in case s gets closed
  gpr_mu_lock(mu);

  if (GRPC_TRACER_ON(grpc_inproc_trace)) {
    if (op->send_initial_metadata) {
      log_metadata(op->payload->send_initial_metadata.send_initial_metadata,
                   s->t->is_client, true);
    }
    if (op->send_trailing_metadata) {
      log_metadata(op->payload->send_trailing_metadata.send_trailing_metadata,
                   s->t->is_client, false);
    }
  }
  grpc_error *error = GRPC_ERROR_NONE;
  grpc_closure *on_complete = op->on_complete;
  if (on_complete == NULL) {
    on_complete = &do_nothing_closure;
  }

  if (op->cancel_stream) {
    // Call cancel_stream_locked without ref'ing the cancel_error because
    // this function is responsible to make sure that that field gets unref'ed
    cancel_stream_locked(exec_ctx, s, op->payload->cancel_stream.cancel_error);
    // this op can complete without an error
  } else if (s->cancel_self_error != GRPC_ERROR_NONE) {
    // already self-canceled so still give it an error
    error = GRPC_ERROR_REF(s->cancel_self_error);
  } else {
    INPROC_LOG(GPR_DEBUG, "perform_stream_op %p%s%s%s%s%s%s", s,
               op->send_initial_metadata ? " send_initial_metadata" : "",
               op->send_message ? " send_message" : "",
               op->send_trailing_metadata ? " send_trailing_metadata" : "",
               op->recv_initial_metadata ? " recv_initial_metadata" : "",
               op->recv_message ? " recv_message" : "",
               op->recv_trailing_metadata ? " recv_trailing_metadata" : "");
  }

  bool needs_close = false;

  if (error == GRPC_ERROR_NONE &&
      (op->send_initial_metadata || op->send_message ||
       op->send_trailing_metadata)) {
    inproc_stream *other = s->other_side;
    if (s->t->is_closed) {
      error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Endpoint already shutdown");
    }
    if (error == GRPC_ERROR_NONE && op->send_initial_metadata) {
      grpc_metadata_batch *dest = (other == NULL) ? &s->write_buffer_initial_md
                                                  : &other->to_read_initial_md;
      uint32_t *destflags = (other == NULL) ? &s->write_buffer_initial_md_flags
                                            : &other->to_read_initial_md_flags;
      bool *destfilled = (other == NULL) ? &s->write_buffer_initial_md_filled
                                         : &other->to_read_initial_md_filled;
      if (*destfilled || s->initial_md_sent) {
        // The buffer is already in use; that's an error!
        INPROC_LOG(GPR_DEBUG, "Extra initial metadata %p", s);
        error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Extra initial metadata");
      } else {
        if (!other->closed) {
          fill_in_metadata(
              exec_ctx, s,
              op->payload->send_initial_metadata.send_initial_metadata,
              op->payload->send_initial_metadata.send_initial_metadata_flags,
              dest, destflags, destfilled);
        }
        if (s->t->is_client) {
          gpr_timespec *dl =
              (other == NULL) ? &s->write_buffer_deadline : &other->deadline;
          *dl = gpr_time_min(*dl, op->payload->send_initial_metadata
                                      .send_initial_metadata->deadline);
          s->initial_md_sent = true;
        }
      }
    }
    if (error == GRPC_ERROR_NONE && op->send_message) {
      size_t remaining = op->payload->send_message.send_message->length;
      grpc_slice_buffer *dest = slice_buffer_list_append(
          (other == NULL) ? &s->write_buffer_message : &other->to_read_message);
      do {
        grpc_slice message_slice;
        grpc_closure unused;
        GPR_ASSERT(grpc_byte_stream_next(exec_ctx,
                                         op->payload->send_message.send_message,
                                         SIZE_MAX, &unused));
        error = grpc_byte_stream_pull(
            exec_ctx, op->payload->send_message.send_message, &message_slice);
        if (error != GRPC_ERROR_NONE) {
          cancel_stream_locked(exec_ctx, s, GRPC_ERROR_REF(error));
          break;
        }
        GPR_ASSERT(error == GRPC_ERROR_NONE);
        remaining -= GRPC_SLICE_LENGTH(message_slice);
        grpc_slice_buffer_add(dest, message_slice);
      } while (remaining != 0);
      grpc_byte_stream_destroy(exec_ctx,
                               op->payload->send_message.send_message);
    }
    if (error == GRPC_ERROR_NONE && op->send_trailing_metadata) {
      grpc_metadata_batch *dest = (other == NULL) ? &s->write_buffer_trailing_md
                                                  : &other->to_read_trailing_md;
      bool *destfilled = (other == NULL) ? &s->write_buffer_trailing_md_filled
                                         : &other->to_read_trailing_md_filled;
      if (*destfilled || s->trailing_md_sent) {
        // The buffer is already in use; that's an error!
        INPROC_LOG(GPR_DEBUG, "Extra trailing metadata %p", s);
        error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Extra trailing metadata");
      } else {
        if (!other->closed) {
          fill_in_metadata(
              exec_ctx, s,
              op->payload->send_trailing_metadata.send_trailing_metadata, 0,
              dest, NULL, destfilled);
        }
        s->trailing_md_sent = true;
        if (!s->t->is_client && s->trailing_md_recvd &&
            s->recv_trailing_md_op) {
          INPROC_LOG(GPR_DEBUG,
                     "perform_stream_op %p scheduling trailing-md-on-complete",
                     s);
          GRPC_CLOSURE_SCHED(exec_ctx, s->recv_trailing_md_op->on_complete,
                             GRPC_ERROR_NONE);
          s->recv_trailing_md_op = NULL;
          needs_close = true;
        }
      }
    }
    if (other != NULL && other->reads_needed) {
      if (!other->read_closure_scheduled) {
        GRPC_CLOSURE_SCHED(exec_ctx, &other->read_closure, error);
        other->read_closure_scheduled = true;
      }
      other->reads_needed = false;
    }
  }
  if (error == GRPC_ERROR_NONE &&
      (op->recv_initial_metadata || op->recv_message ||
       op->recv_trailing_metadata)) {
    // If there are any reads, mark it so that the read closure will react to
    // them
    if (op->recv_initial_metadata) {
      s->recv_initial_md_op = op;
    }
    if (op->recv_message) {
      s->recv_message_op = op;
    }
    if (op->recv_trailing_metadata) {
      s->recv_trailing_md_op = op;
    }

    // We want to initiate the closure if:
    // 1. There is initial metadata and something ready to take that
    // 2. There is a message and something ready to take it
    // 3. There is trailing metadata, even if nothing specifically wants
    //    that because that can shut down the message as well
    if ((s->to_read_initial_md_filled && op->recv_initial_metadata) ||
        ((!slice_buffer_list_empty(&s->to_read_message) ||
          s->trailing_md_recvd) &&
         op->recv_message) ||
        (s->to_read_trailing_md_filled)) {
      if (!s->read_closure_scheduled) {
        GRPC_CLOSURE_SCHED(exec_ctx, &s->read_closure, GRPC_ERROR_NONE);
        s->read_closure_scheduled = true;
      }
    } else {
      s->reads_needed = true;
    }
  } else {
    if (error != GRPC_ERROR_NONE) {
      // Schedule op's read closures that we didn't push to read state machine
      if (op->recv_initial_metadata) {
        INPROC_LOG(
            GPR_DEBUG,
            "perform_stream_op error %p scheduling initial-metadata-ready %p",
            s, error);
        GRPC_CLOSURE_SCHED(
            exec_ctx,
            op->payload->recv_initial_metadata.recv_initial_metadata_ready,
            GRPC_ERROR_REF(error));
      }
      if (op->recv_message) {
        INPROC_LOG(
            GPR_DEBUG,
            "perform_stream_op error %p scheduling recv message-ready %p", s,
            error);
        GRPC_CLOSURE_SCHED(exec_ctx,
                           op->payload->recv_message.recv_message_ready,
                           GRPC_ERROR_REF(error));
      }
    }
    INPROC_LOG(GPR_DEBUG, "perform_stream_op %p scheduling on_complete %p", s,
               error);
    GRPC_CLOSURE_SCHED(exec_ctx, on_complete, GRPC_ERROR_REF(error));
  }
  if (needs_close) {
    close_other_side_locked(exec_ctx, s, "perform_stream_op:other_side");
    close_stream_locked(exec_ctx, s);
  }
  gpr_mu_unlock(mu);
  GRPC_ERROR_UNREF(error);
}