123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232 |
- 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.
|