|  | # QUIC network simulator | 
|  |  | 
|  | This directory contains a discrete event network simulator which QUIC code uses | 
|  | for testing congestion control and other transmission control code that requires | 
|  | a network simulation for tests on QuicConnection level of abstraction. | 
|  |  | 
|  | ## Actors | 
|  |  | 
|  | The core of the simulator is the Simulator class, which maintains a virtual | 
|  | clock and an event queue. Any object in a simulation that needs to schedule | 
|  | events has to subclass Actor. Subclassing Actor involves: | 
|  |  | 
|  | 1.  Calling the `Actor::Actor(Simulator*, std::string)` constructor to establish | 
|  | the name of the object and the simulator it is associated with. | 
|  | 2.  Calling `Schedule(QuicTime)` to schedule the time at which `Act()` method is | 
|  | called. `Schedule` will only cause the object to be rescheduled if the time | 
|  | for which it is currently scheduled is later than the new time. | 
|  | 3.  Implementing `Act()` method with the relevant logic. The actor will be | 
|  | removed from the event queue right before `Act()` is called. | 
|  |  | 
|  | Here is a simple example of an object that outputs simulation time into the log | 
|  | every 100 ms. | 
|  |  | 
|  | ```c++ | 
|  | class LogClock : public Actor { | 
|  | public: | 
|  | LogClock(Simulator* simulator, std::string name) : Actor(simulator, name) { | 
|  | Schedule(clock_->Now()); | 
|  | } | 
|  | ~LogClock() override {} | 
|  |  | 
|  | void Act() override { | 
|  | QUIC_LOG(INFO) << "The current time is " | 
|  | << clock_->Now().ToDebuggingValue(); | 
|  | Schedule(clock_->Now() + QuicTime::Delta::FromMilliseconds(100)); | 
|  | } | 
|  | }; | 
|  | ``` | 
|  |  | 
|  | A QuicAlarm object can be used to schedule events in the simulation using | 
|  | `Simulator::GetAlarmFactory()`. | 
|  |  | 
|  | ## Ports | 
|  |  | 
|  | The simulated network transfers packets, which are modelled as an instance of | 
|  | struct `Packet`. A packet consists of source and destination address (which are | 
|  | just plain strings), a transmission timestamp and the UDP-layer payload. | 
|  |  | 
|  | The simulation uses the push model: any object that wishes to transfer a packet | 
|  | to another component in the simulation has to explicitly do it itself. Any | 
|  | object that can accept a packet is called a *port*. There are two types of | 
|  | ports: unconstrained ports, which can always accept packets, and constrained | 
|  | ports, which signal when they can accept a new packet. | 
|  |  | 
|  | An endpoint is an object that is connected to the network and can both receive | 
|  | and send packets. In our model, the endpoint always receives packets as an | 
|  | unconstrained port (*RX port*), and always writes packets to a constrained port | 
|  | (*TX port*). | 
|  |  | 
|  | ## Links | 
|  |  | 
|  | The `SymmetricLink` class models a symmetric duplex links with finite bandwidth | 
|  | and propagation delay. It consists of a pair of identical `OneWayLink`s, which | 
|  | accept packets as a constrained port (where constrain comes from the finiteness | 
|  | of bandwidth) and outputs them into an unconstrained port. Two endpoints | 
|  | connected via a `SymmetricLink` look like this: | 
|  |  | 
|  | ```none | 
|  | Endpoint A                                                 Endpoint B | 
|  | +-----------+                 SymmetricLink                +-----------+ | 
|  | |           |       +------------------------------+       |           | | 
|  | |      +---------+  |  +------------------------+  |  +---------+      | | 
|  | |      | RX port <-----|       OneWayLink      *<-----| TX port |      | | 
|  | |      +---------+  |  +------------------------+  |  +---------+      | | 
|  | |           |       |                              |       |           | | 
|  | |      +---------+  |  +------------------------+  |  +---------+      | | 
|  | |      | TX port |----->*      OneWayLink       |-----> RX port |      | | 
|  | |      +---------+  |  +------------------------+  |  +---------+      | | 
|  | |           |       +------------------------------+       |           | | 
|  | +-----------+                                              +-----------+ | 
|  |  | 
|  | ( -->* denotes constrained port) | 
|  | ``` | 
|  |  | 
|  | In most common scenario, one of the endpoints is going to be a QUIC endpoint, | 
|  | and another is going to be a switch port. | 
|  |  | 
|  | ## Other objects | 
|  |  | 
|  | Besides `SymmetricLink`, the simulator provides the following objects: | 
|  |  | 
|  | *   `Queue` allows to convert a constrained port into an unconstrained one by | 
|  | buffering packets upon arrival. The queue has a finite size, and once the | 
|  | queue is full, the packets are silently dropped. | 
|  | *   `Switch` simulates a multi-port learning switch with a fixed queue for each | 
|  | output port. | 
|  | *   `QuicEndpoint` allows QuicConnection to be run over the simulated network. | 
|  | *   `QuicEndpointMultiplexer` allows multiple connections to share the same | 
|  | network endpoint. |