Пример #1
0
		/// <summary>
		/// Initializes a new instance of the Nic class using the specified
		/// MAC address.
		/// </summary>
		/// <param name="address">A MAC-48 address to assign to the NIC. If this
		/// is null, the NIC is assigned a random MAC address.</param>
		protected Nic(MacAddress address = null) {
			if (address != null)
				MacAddress = address;
			else
				MacAddress = new MacAddress();
			Connector = new Connector();
		}
Пример #2
0
        /// <summary>
        /// Pierces the cable and wires the specified connector to at the specified position.
        /// </summary>
        /// <param name="position">The position at which to pierce the cable.</param>
        /// <param name="connector">The connector to wire to the cable at the pierced
        /// position.</param>
        /// <returns>A reference to the C10Base5 instance for chaining.</returns>
        /// <exception cref="InvalidOperationException">Another connector has already been
        /// installed at the specified position.</exception>
        /// <exception cref="InvalidOperationException">As per IEEE 802.3 specification the
        /// position at which the cable is pierced must be a multiple of 2.5 metres.</exception>
		public C10Base5 Pierce(double position, Connector connector) {
			if (connectors.Values.Contains(position))
				throw new InvalidOperationException("The position is already taken.");
			if (Math.Abs(position % 2.5) > 0.1)
				throw new InvalidOperationException("Position must be a multiple of 2.5.");
			connectors.Add(connector, position);
			connector.Cable = this;
			return this;
		}
Пример #3
0
		/// <summary>
		/// Initializes a new instance of the Bridge class.
		/// </summary>
		/// <param name="numPorts">The number of I/O ports.</param>
		/// <param name="delay">The inherent propagation delay of the bridge.</param>
		public Bridge(int numPorts, ulong delay) {
			for (var i = 0; i < numPorts; i++) {
				var c = new Connector();
				c.SignalSense += (sender, e) => OnSignalSense(c);
				c.SignalCease += (sender, e) => OnSignalCease(c, sender, e);
				ports.Add(c);
				// House-keeping.
				InitFields(c);
			}
		}
Пример #4
0
		/// <summary>
		/// Creates the needed entries in the various dictionaries for the
		/// specified connector.
		/// </summary>
		/// <param name="connector">The connector to initialize.</param>
		void InitFields(Connector connector) {
			tx.Add(connector, false);
			rx.Add(connector, false);
			retransmissionCount.Add(connector, 0);
			transmissionData.Add(connector, null);

			inputFifo.Add(connector, new CappedQueue<Frame>());
			outputFifo.Add(connector, new CappedQueue<Frame>());
			waitTime.Add(connector, 0);
			isIdle.Add(connector, true);
		}
Пример #5
0
        /// <summary>
        /// Attach the specified connector to the cable at the specified position.
        /// </summary>
        /// <param name="position">The position at which to connect the connector to the
        /// cable.</param>
        /// <param name="connector">The connector to connect to the cable at the specified
        /// position.</param>
        /// <exception cref="InvalidOperationException">Another connector has already been
        /// installed at the specified position.</exception>
        /// <exception cref="InvalidOperationException">As per 10BASE2 specification the
        /// position at which a station is connected must be a multiple of 0.5 metres.
        /// </exception>
		public void Attach(double position, Connector connector) {
			if (connectors.Values.Contains(position))
				throw new InvalidOperationException("The position is already taken.");
			if (Math.Abs(position % 0.5) > .0)
				throw new InvalidOperationException("Position must be a multiple of 0.5.");
			if (connectors.ContainsKey(connector))
				throw new InvalidOperationException("Connector is already attached at " +
					connectors[connector] + ".");
			connectors.Add(connector, position);
			connector.Cable = this;
		}
Пример #6
0
		/// <summary>
		/// Invokes the specified action for every connector within the
		/// collision domain, excluding those connected through the specified
		/// inport.
		/// </summary>
		/// <param name="inport">The port through which the signal is being
		/// received.</param>
		/// <param name="action">The action to invoke.</param>
		void Repeat(Connector inport, Action<Connector, ulong> action) {
			foreach (var c in ports) {
				if (!c.IsConnected || c == inport)
					continue;
				var pos = c.Cable.Connectors[c];
				foreach (var pair in c.Cable.Connectors) {
					if (pair.Key == c)
						continue;
					var dist = Math.Abs(pos - pair.Value);
					var propDelayNs = (ulong) (1000000000 *
						(dist / c.Cable.PropagationSpeed));
					action(pair.Key, Delay + propDelayNs);
				}
			}
		}
Пример #7
0
		/// <summary>
		/// Initializes a new instance of the Hub class.
		/// </summary>
		/// <param name="numPorts">The number of I/O ports.</param>
		/// <param name="delay">The inherent propagation delay of the hub.</param>
		public Hub(int numPorts, ulong delay) {
			for (var i = 0; i < numPorts; i++) {
				var c = new Connector();
				c.SignalSense += (sender, e) => {
					Repeat(c, (other, propDelay) =>
						Simulation.AddEvent(new SignalSenseEvent(propDelay,
							other, sender)));
				};
				c.SignalCease += (sender, e) => {
					Repeat(c, (other, propDelay) =>
						Simulation.AddEvent(new SignalCeaseEvent(propDelay,
							other, e.Data, sender)));
				};
				ports.Add(c);
			}
		}
Пример #8
0
	    /// <summary>
	    /// Starts the actual data transfer.
	    /// </summary>
	    /// <param name="connector"></param>
	    /// <param name="data">The data to transmit.</param>
	    void StartTransmission(Connector connector, byte[] data) {
			// If the medium is no longer idle at this point, start over.
			if (rx[connector]) {
				Transmit(connector, data);
				return;
			}
			WritePhy("Starting transmission.");
			tx[connector] = true;
			transmissionData[connector] = data;
			connector.Transmit(data);
		}
Пример #9
0
        /// <summary>
        /// Simulates the transmission of data from the specified source.
        /// </summary>
        /// <param name="source">The connector from which data is being transmitted.</param>
        /// <param name="data">The data that is being transmitted from the source.</param>
		public void Transmit(Connector source, byte[] data) {
			source.ThrowIfNull("source");
			data.ThrowIfNull("data");
			var position = connectors[source];
			// Simulate physical frame corruption.
			if (HasNoise)
				data = DistortSignal(data);
			// Calculate transmission time = Size / Bitrate.
			var transTimeNs = (ulong) (1000000000 *
				(data.Length * 8 / (double) Bitrate));
			// Calculate events for each device on the cable.
			foreach (var pair in connectors) {
				var distance = Math.Abs(position - pair.Value);
				// Propagation delay in nanoseconds.
				var propDelayNs = (ulong) (1000000000 *
					(distance / PropagationSpeed));
				var deliveryTimeNs = propDelayNs + transTimeNs;
				Simulation.AddEvent(
					new SignalSenseEvent(propDelayNs, pair.Key, source));
				Simulation.AddEvent(
					new SignalCeaseEvent(deliveryTimeNs, pair.Key, data, source));
			}
		}
Пример #10
0
        /// <summary>
        /// Simulates the transmission of a Jam signal.
        /// </summary>
        /// <param name="source">The source sending the Jam signal.</param>
        /// <returns>The time it takes to transmit the Jam signal, in nanoseconds.</returns>
		public ulong Jam(Connector source) {
			Simulation.RemoveEvents(ev => ev is SignalCeaseEvent &&
				ev.Sender == source);
			var position = connectors[source];
			// Calculate the transmission time.
			var transTimeNs = (ulong) (1000000000 * (48 / (double) Bitrate));
			// Calculate the propagation delay and delivery time for each
			// NIC within the collision domain.
			foreach (var pair in connectors) {
				var distance = Math.Abs(position - pair.Value);
				var propDelayNs = (ulong) (1000000000 *
					(distance / PropagationSpeed));
				var deliveryTimeNs = propDelayNs + transTimeNs;
				Simulation.AddEvent(
					new SignalCeaseEvent(deliveryTimeNs, pair.Key, null, source));
			}
			return transTimeNs;
		}
Пример #11
0
		/// <summary>
		/// Invoked om behalf of PHY whenever a frame has been transmitted.
		/// </summary>
		void OnDataTransmitted(Connector connector) {
			WriteMac("Finished transmitting Ethernet frame.");
			isIdle[connector] = true;
			waitTime[connector] = Simulation.Time + interframeGapTime(connector);
		}
Пример #12
0
	    /// <summary>
	    /// Invoked on behalf of PHY whenever new data has been received.
	    /// </summary>
	    /// <param name="connector"></param>
	    /// <param name="data">The data that was received.</param>
	    void OnDataReceived(Connector connector, byte[] data) {
			data.ThrowIfNull("data");
			WriteMac("Received an Ethernet frame.");
			waitTime[connector] = Simulation.Time + interframeGapTime(connector);
			var frame = Frame.Deserialize(data);
			// Compute checksum and compare to the one contained in the frame.
			var fcs = Frame.ComputeCheckSequence(frame);
			if (fcs != frame.CheckSequence) {
				WriteMac("Detected a bad frame check sequence, discarding.");
				return;
			}
			// Remember the port through which the frame came in.
			forwardTable[frame.Source] = connector;
			// If we know the destination and it's on the same port as the
			// source, discard the frame.
			if (forwardTable.ContainsKey(frame.Destination)) {
				if (forwardTable[frame.Source] == forwardTable[frame.Destination])
					return;
			}
			// Start emptying the FIFO, if we're not already doing it.
			if (emptyingFifos == false)
				Simulation.Callback(0, EmptyFifos);
			// Enqueue the data.
			inputFifo[connector].Enqueue(frame);
		}
Пример #13
0
	    /// <summary>
	    /// Performs the exponential backoff algorithm of CSMA/CD.
	    /// </summary>
	    /// <param name="connector"></param>
	    /// <param name="deltaTime"></param>
	    void ExponentialBackoff(Connector connector, ulong deltaTime) {
			retransmissionCount[connector]++;
			if (retransmissionCount[connector] >= maxRetransmissions) {
				AbortTransmission(connector);
			} else {
				// Wait a random number of slot-times, with a slot-time being
				// defined as the transmission time of 512 bits.
				// (Cmp, "Computer Networks", 5th Ed., A. Tanenbaum, p.285)
				var c = random.Next((int) Math.Pow(2,
					Math.Min(retransmissionCount[connector], maxExponentiation)));
				// (Ex., the slot-time on 10Mbps Ethernet is 51.2µsec)
				var slotTime = (ulong) ((512 / (double)
					configuredBitrate(connector)) * 1000000000);
				var _waitTime = (ulong) c * slotTime;
				WritePhy("Waiting for " + _waitTime + " (" + c +
					" slot times), " + retransmissionCount + ".Try, Total = " +
					(deltaTime + _waitTime));
				Simulation.Callback(deltaTime + _waitTime,
					() => Transmit(connector, transmissionData[connector]));
			}
		}
Пример #14
0
		int configuredBitrate(Connector connector) {
			return connector.Cable.Bitrate;
		}
Пример #15
0
		/// <summary>
		/// Aborts a scheduled data transmission.
		/// </summary>
		void AbortTransmission(Connector connector) {
			WritePhy("Transmission failed! Maximum retransmission " +
				"threshold reached.");
			// Reset retransmission counter.
			retransmissionCount[connector] = 0;
		}
Пример #16
0
		ulong interframeGapTime(Connector connector) {
			return (ulong) ((96 / (double) configuredBitrate(connector)) *
				1000000000);
		}
Пример #17
0
	    /// <summary>
	    /// Transmits the specified data.
	    /// </summary>
	    /// <param name="connector"></param>
	    /// <param name="data">The data to transmit.</param>
	    void Transmit(Connector connector, byte[] data) {
			// Defer transmission until medium becomes idle.
			if (rx[connector]) {
				// Poll medium about every 10µs.
				var timeout = (ulong) (10000 + random.Next(5000));
				WritePhy("Deferring transmission, next try at " + timeout);
				Simulation.Callback(timeout, () => Transmit(connector, data));
			} else {
				// Must wait another interframe-gap, before we can proceed.
				Simulation.Callback(interframeGapTime(connector),
					() => StartTransmission(connector, data));
			}
		}
Пример #18
0
	    /// <summary>
	    /// Invoked whenever the carrier signal ceases.
	    /// </summary>
	    /// <param name="connector">The connector which is no longer
	    /// sensing a signal.</param>
	    /// <param name="sender"></param>
	    /// <param name="e"></param>
	    void OnSignalCease(Connector connector, object sender, SignalCeaseEventArgs e) {
			if (tx[connector])
				WritePhy("Finished transmitting bits.");
			rx[connector] = false;
			tx[connector] = false;
			// Hand data to MAC-layer.
			if (e.IsJam) {
				WritePhy("Receiving a jam signal.");
				return;
			}
			if (sender == connector)
				OnDataTransmitted(connector);
			else
				OnDataReceived(connector, e.Data);
		}
Пример #19
0
		/// <summary>
		/// Invoked whenever the receiver senses a signal.
		/// </summary>
		/// <param name="connector">The connector sensing a signal.</param>
		void OnSignalSense(Connector connector) {
			WritePhy("Sensing a carier.");
			if (rx[connector] && tx[connector]) {
				// Collision.
				WritePhy("Collision detected.");
				var jamTime = connector.Jam();
				ExponentialBackoff(connector, jamTime);
			} else {
				rx[connector] = true;
			}
		}