// 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; }