// This is all-or-nothing.
nsresult TransportFlow::PushLayers(nsAutoPtr<std::queue<TransportLayer *> > layers) {
  MOZ_ASSERT(!layers->empty());
  if (layers->empty()) {
    MOZ_MTLOG(PR_LOG_ERROR, id_ << ": Can't call PushLayers with empty layers");
    return NS_ERROR_INVALID_ARG;
  }

  // Don't allow pushes once we are in error state.
  if (state_ == TransportLayer::TS_ERROR) {
    MOZ_MTLOG(PR_LOG_ERROR, id_ << ": Can't call PushLayers in error state for flow ");
    return NS_ERROR_FAILURE;
  }

  nsresult rv = NS_OK;

  // Disconnect all the old signals.
  disconnect_all();

  TransportLayer *layer;

  while (!layers->empty()) {
    TransportLayer *old_layer = layers_.empty() ? nullptr : layers_.front();
    layer = layers->front();

    rv = layer->Init();
    if (NS_FAILED(rv)) {
      MOZ_MTLOG(PR_LOG_ERROR, id_ << ": Layer initialization failed; invalidating flow ");
      break;
    }

    // Push the layer onto the queue.
    layers_.push_front(layer);
    layers->pop();
    layer->Inserted(this, old_layer);
  }

  if (NS_FAILED(rv)) {
    // Destroy any layers we could not push.
    while (!layers->empty()) {
      delete layers->front();
      layers->pop();
    }

    // Now destroy the rest of the flow, because it's no longer
    // in an acceptable state.
    while (!layers_.empty()) {
      delete layers_.front();
      layers_.pop_front();
    }

    // Set ourselves to have failed.
    StateChangeInt(TransportLayer::TS_ERROR);

    // Return failure.
    return rv;
  }

  // Finally, attach ourselves to the top layer.
  layer->SignalStateChange.connect(this, &TransportFlow::StateChange);
  layer->SignalPacketReceived.connect(this, &TransportFlow::PacketReceived);
  StateChangeInt(layer->state());  // Signals if the state changes.

  return NS_OK;
}