瀏覽代碼

Added basic bandwidth measurement on IP networks

git-svn-id: https://svn.inf.ethz.ch/svn/lecturers/a2/trunk@8679 8c9fc860-2736-0410-a75d-ab315db34111
negelef 6 年之前
父節點
當前提交
ec9f281916
共有 2 個文件被更改,包括 234 次插入0 次删除
  1. 232 0
      source/IPBandwidth.Mod
  2. 2 0
      source/Release.Tool

+ 232 - 0
source/IPBandwidth.Mod

@@ -0,0 +1,232 @@
+MODULE IPBandwidth;	(** AUTHOR "negelef"; PURPOSE "Bandwidth measurement on IP networks."; *)
+
+IMPORT Commands, Diagnostics, Kernel, Options, Streams, DNS, IP, TCP, UDP;
+
+CONST DefaultPort = 5772;
+CONST DefaultDuration = 10;
+
+TYPE Link = OBJECT
+
+	VAR context: Commands.Context;
+	VAR diagnostics: Diagnostics.StreamDiagnostics;
+	VAR hostname: DNS.Name;
+	VAR port, result: WORD;
+	VAR address: IP.Adr;
+	VAR buffer: ARRAY 65000 OF CHAR;
+
+	PROCEDURE &Initialize (context: Commands.Context);
+	BEGIN
+		SELF.context := context;
+		NEW (diagnostics, context.error);
+	END Initialize;
+
+	PROCEDURE Send;
+	VAR sent: SIZE;
+	BEGIN
+		IF ~context.arg.GetString (hostname) THEN
+			context.result := Commands.CommandParseError; RETURN;
+		END;
+		DNS.HostByName (hostname, address, result);
+		IF result # DNS.Ok THEN
+			diagnostics.Error (hostname, port, "failed to resolve");
+			context.result := Commands.CommandError; RETURN;
+		END;
+		IF ~context.arg.GetInteger (port, FALSE) THEN
+			port := DefaultPort;
+		END;
+
+		Connect;
+		IF result # Streams.Ok THEN
+			diagnostics.Error (hostname, port, "failed to connect to server");
+			context.result := Commands.CommandError; RETURN;
+		END;
+
+		sent := 0;
+		context.out.String ("Sending data..."); context.out.Ln; context.out.Update;
+		WHILE ReceiveBytes () = 0 DO
+			INC (sent, SendBytes ());
+			IF result # Streams.Ok THEN
+				Close;
+				diagnostics.Error (hostname, port, "failed to send");
+				context.result := Commands.CommandError; RETURN;
+			END;
+		END;
+
+		Close;
+		context.out.String ("Sent "); context.out.Size (sent); context.out.String (" bytes"); context.out.Ln; context.out.Update;
+	END Send;
+
+	PROCEDURE Receive;
+	VAR duration, ticks: WORD; received: SIZE;
+	BEGIN
+		hostname := "server";
+		IF ~context.arg.GetInteger (duration, FALSE) THEN
+			duration := DefaultDuration;
+		END;
+		IF ~context.arg.GetInteger (port, FALSE) THEN
+			port := DefaultPort;
+		END;
+
+		Listen;
+		IF result # Streams.Ok THEN
+			diagnostics.Error (hostname, port, "failed to connect to client");
+			context.result := Commands.CommandError; RETURN;
+		END;
+
+		received := 0; ticks := 0;
+		context.out.String ("Receiving data..."); context.out.Ln; context.out.Update;
+		LOOP
+			INC (received, ReceiveBytes ());
+			IF result # Streams.Ok THEN
+				Close;
+				diagnostics.Error (hostname, port, "failed to receive");
+				context.result := Commands.CommandError; RETURN;
+			END;
+			IF ticks = 0 THEN
+				IF received # 0 THEN ticks := Kernel.GetTicks () + Kernel.second * duration END;
+			ELSE
+				IF Kernel.GetTicks () - ticks >= 0 THEN EXIT END;
+			END;
+		END;
+
+		Close;
+		context.out.String ("Received "); context.out.Size (received); context.out.String (" bytes in ");
+		context.out.Int (duration, 0); context.out.String (" seconds"); context.out.Ln;
+		context.out.String ("Bandwidth: "); context.out.FloatFix (received / (1000000 * duration), 0, 3, 0);
+		context.out.String (" MB/s"); context.out.Ln; context.out.Update;
+	END Receive;
+
+	PROCEDURE Connect;
+	BEGIN HALT (1001);
+	END Connect;
+
+	PROCEDURE Listen;
+	BEGIN HALT (1001);
+	END Listen;
+
+	PROCEDURE SendBytes (): Streams.StreamSize;
+	BEGIN HALT (1001);
+	END SendBytes;
+
+	PROCEDURE ReceiveBytes (): Streams.StreamSize;
+	BEGIN HALT (1001);
+	END ReceiveBytes;
+
+	PROCEDURE Close;
+	BEGIN HALT (1001);
+	END Close;
+
+END Link;
+
+TYPE TCPLink = OBJECT (Link)
+
+	VAR service, connection: TCP.Connection;
+
+	PROCEDURE Connect;
+	BEGIN
+		NEW (connection);
+		connection.Open (TCP.NilPort, address, port, result);
+	END Connect;
+
+	PROCEDURE Listen;
+	BEGIN
+		NEW (service);
+		service.Open (port, IP.NilAdr, TCP.NilPort, result);
+		IF result = TCP.Ok THEN
+			context.out.String ("Waiting for client..."); context.out.Ln; context.out.Update;
+			service.Accept (connection, result);
+		END;
+	END Listen;
+
+	PROCEDURE SendBytes (): Streams.StreamSize;
+	BEGIN
+		connection.Send (buffer, 0, LEN (buffer), FALSE, result);
+		RETURN LEN (buffer);
+	END SendBytes;
+
+	PROCEDURE ReceiveBytes (): Streams.StreamSize;
+	VAR received: WORD;
+	BEGIN
+		IF connection.Available () # 0 THEN
+			connection.Receive (buffer, 0, LEN (buffer), 1, received, result);
+			IF result = TCP.Ok THEN RETURN received END;
+		END;
+		RETURN 0;
+	END ReceiveBytes;
+
+	PROCEDURE Close;
+	BEGIN
+		connection.Close;
+		IF service # NIL THEN service.Close END;
+	END Close;
+
+END TCPLink;
+
+TYPE UDPLink = OBJECT (Link)
+
+	VAR socket: UDP.Socket;
+
+	PROCEDURE Connect;
+	BEGIN
+		NEW (socket, UDP.NilPort, result);
+	END Connect;
+
+	PROCEDURE Listen;
+	BEGIN
+		NEW (socket, port, result);
+	END Listen;
+
+	PROCEDURE SendBytes (): Streams.StreamSize;
+	BEGIN
+		socket.Send (address, port, buffer, 0, LEN (buffer), result);
+		RETURN LEN (buffer);
+	END SendBytes;
+
+	PROCEDURE ReceiveBytes (): Streams.StreamSize;
+	VAR address: IP.Adr; port, received: WORD;
+	BEGIN
+		socket.Receive (buffer, 0, LEN (buffer), 0, address, port, received, result);
+		IF result = UDP.Ok THEN RETURN received END;
+		IF result = UDP.Timeout THEN result := UDP.Ok END;
+		RETURN 0;
+	END ReceiveBytes;
+
+	PROCEDURE Close;
+	BEGIN socket.Close;
+	END Close;
+
+END UDPLink;
+
+(** Synposis: hostname [port] *)
+PROCEDURE SendTCP* (context: Commands.Context);
+VAR link: TCPLink;
+BEGIN
+	NEW (link, context);
+	link.Send;
+END SendTCP;
+
+(** Synposis: [duration] [port] *)
+PROCEDURE ReceiveTCP* (context: Commands.Context);
+VAR link: TCPLink; client: TCP.Connection;
+BEGIN
+	NEW (link, context);
+	link.Receive;
+END ReceiveTCP;
+
+(** Synposis: hostname [port] *)
+PROCEDURE SendUDP* (context: Commands.Context);
+VAR link: UDPLink;
+BEGIN
+	NEW (link, context);
+	link.Send;
+END SendUDP;
+
+(** Synposis: [duration] [port] *)
+PROCEDURE ReceiveUDP* (context: Commands.Context);
+VAR link: UDPLink;
+BEGIN
+	NEW (link, context);
+	link.Receive;
+END ReceiveUDP;
+
+END IPBandwidth.

+ 2 - 0
source/Release.Tool

@@ -947,6 +947,8 @@ PACKAGE Applications ARCHIVE "Applications.zip" SOURCE "ApplicationsSrc.zip" DES
 	TCPServices.Mod TestServer.Mod	# TCP services
 	TCPTools.Mod						# Some useful TCP-related commands
 
+	IPBandwidth.Mod
+
 	BIOS & ~COOP { Performance.Mod }
 	WIN, UNIX, BIOS & COOP, ZYNQ { Windows.Performance.Mod } # This is just a dummy