mirror of
https://github.com/vishapoberon/compiler.git
synced 2026-04-06 15:42:25 +00:00
Update tools to v2.
This commit is contained in:
parent
ce855c93c8
commit
8b0bd9c675
8 changed files with 1742 additions and 86 deletions
283
src/tools/testcoordinator/IP.Mod
Normal file
283
src/tools/testcoordinator/IP.Mod
Normal file
|
|
@ -0,0 +1,283 @@
|
|||
MODULE IP;
|
||||
|
||||
IMPORT SYSTEM, Platform, Console;
|
||||
|
||||
CONST
|
||||
FDcount- = 1024; (* Number of FDs in FD set *)
|
||||
|
||||
TYPE
|
||||
SocketAddress* = RECORD
|
||||
length-: LONGINT;
|
||||
buf: ARRAY 28 OF SYSTEM.BYTE; (* Sufficient for IPv4 and IPv6. *)
|
||||
END;
|
||||
FDset* = ARRAY 128 OF SYSTEM.BYTE; (* Exposes C fd_set *)
|
||||
|
||||
InAddr = POINTER TO InAddrDesc;
|
||||
InAddrDesc = RECORD
|
||||
addr: ARRAY 128 OF SYSTEM.BYTE;
|
||||
next: InAddr
|
||||
END;
|
||||
|
||||
VAR
|
||||
v4-: LONGINT; (* AF_INET *)
|
||||
v6-: LONGINT; (* AF_INET6 *)
|
||||
Stream-: LONGINT; (* SOCK_STREAM *)
|
||||
Datagram-: LONGINT; (* SOCK_DGRAM *)
|
||||
|
||||
|
||||
(* Testing *)
|
||||
|
||||
addr: InAddr;
|
||||
err: Platform.ErrorCode;
|
||||
|
||||
|
||||
PROCEDURE -AAincludetypes "#include <sys/types.h>";
|
||||
PROCEDURE -AAincludetime "#include <sys/time.h>";
|
||||
PROCEDURE -AAincludesocket "#include <sys/socket.h>";
|
||||
PROCEDURE -AAincludeselect "#include <sys/select.h>";
|
||||
PROCEDURE -AAincludenetdb "#include <netdb.h>";
|
||||
|
||||
|
||||
PROCEDURE -AICANONNAME (): LONGINT "AI_CANONNAME";
|
||||
PROCEDURE -AIPASSIVE (): LONGINT "AI_PASSIVE ";
|
||||
PROCEDURE -AFUNSPEC (): LONGINT "AF_UNSPEC";
|
||||
PROCEDURE -AFINET (): LONGINT "AF_INET";
|
||||
PROCEDURE -AFINET6 (): LONGINT "AF_INET6";
|
||||
PROCEDURE -SOCKSTREAM (): LONGINT "SOCK_STREAM";
|
||||
PROCEDURE -SOCKDGRAM (): LONGINT "SOCK_DGRAM";
|
||||
PROCEDURE -NINUMERICHOST(): LONGINT "NI_NUMERICHOST";
|
||||
PROCEDURE -NINUMERICSERV(): LONGINT "NI_NUMERICSERV";
|
||||
PROCEDURE -EAISYSTEM (): LONGINT "EAI_SYSTEM";
|
||||
PROCEDURE -EAIFAIL (): LONGINT "EAI_FAIL";
|
||||
|
||||
|
||||
(* Console output convenience APIs *)
|
||||
|
||||
PROCEDURE cs (s: ARRAY OF CHAR); BEGIN Console.String(s) END cs;
|
||||
PROCEDURE csl(s: ARRAY OF CHAR); BEGIN Console.String(s); Console.Ln END csl;
|
||||
PROCEDURE ci (i,w: LONGINT); BEGIN Console.Int(i,w) END ci;
|
||||
PROCEDURE ch (i: LONGINT); BEGIN Console.Hex(i) END ch;
|
||||
PROCEDURE cc (c: CHAR); BEGIN Console.Char(c) END cc;
|
||||
PROCEDURE cl (); BEGIN Console.Ln END cl;
|
||||
PROCEDURE hex(i: INTEGER): CHAR;
|
||||
BEGIN IF i < 10 THEN RETURN CHR(i+48) ELSE RETURN CHR(i+55) END END hex;
|
||||
PROCEDURE cb (b: SYSTEM.BYTE);
|
||||
VAR v: INTEGER;
|
||||
BEGIN
|
||||
v := SYSTEM.VAL(INTEGER, b); cc(hex(v DIV 16)); cc(hex(v MOD 16));
|
||||
END cb;
|
||||
|
||||
|
||||
PROCEDURE -getnameinfo(sa, salen, flags: LONGINT; VAR host, serv: ARRAY OF CHAR): INTEGER
|
||||
"(INTEGER)getnameinfo((const struct sockaddr*)sa, salen, host, host__len, serv, serv__len, flags)";
|
||||
|
||||
PROCEDURE WriteSocketAddress*(s: SocketAddress);
|
||||
VAR host, service: ARRAY 4096 OF CHAR; IPv6: BOOLEAN;
|
||||
BEGIN
|
||||
IPv6 := s.length > 20; (* IPv4 len = 16, IPv6 len = 28 *)
|
||||
IF getnameinfo(SYSTEM.ADR(s.buf), s.length, NINUMERICHOST(), host, service) >= 0 THEN
|
||||
IF IPv6 THEN cc('[') END; cs(host); IF IPv6 THEN cs("]:") ELSE cc(':') END;
|
||||
cs(service)
|
||||
END
|
||||
END WriteSocketAddress;
|
||||
|
||||
PROCEDURE SameAddress*(s1, s2: SocketAddress): BOOLEAN;
|
||||
(* True if same IP address, independent of port number *)
|
||||
VAR host1, host2, service: ARRAY 4096 OF CHAR; i: INTEGER; result: BOOLEAN;
|
||||
BEGIN
|
||||
result := getnameinfo(SYSTEM.ADR(s1.buf), s1.length, NINUMERICHOST(), host1, service) >= 0;
|
||||
IF result THEN result := getnameinfo(SYSTEM.ADR(s2.buf), s2.length, NINUMERICHOST(), host2, service) >= 0 END;
|
||||
cs("host1: '"); cs(host1); cs("', host2: '"); cs(host2); csl("'.");
|
||||
IF result THEN
|
||||
i := 0;
|
||||
WHILE (host1[i] # 0X) & (host2[i] # 0X) & (host1[i] = host2[i]) DO INC(i) END;
|
||||
result := host1[i] = host2[i]
|
||||
END;
|
||||
RETURN result;
|
||||
END SameAddress;
|
||||
|
||||
PROCEDURE -aiFlags (p: LONGINT): LONGINT "(LONGINT)((struct addrinfo*)p)->ai_flags";
|
||||
PROCEDURE -aiFamily (p: LONGINT): LONGINT "(LONGINT)((struct addrinfo*)p)->ai_family";
|
||||
PROCEDURE -aiSocketType(p: LONGINT): LONGINT "(LONGINT)((struct addrinfo*)p)->ai_socktype";
|
||||
PROCEDURE -aiProtocol (p: LONGINT): LONGINT "(LONGINT)((struct addrinfo*)p)->ai_protocol";
|
||||
PROCEDURE -aiAddrLen (p: LONGINT): LONGINT "(LONGINT)((struct addrinfo*)p)->ai_addrlen";
|
||||
PROCEDURE -aiSockAddr (p: LONGINT): LONGINT "(LONGINT)((struct addrinfo*)p)->ai_addr";
|
||||
PROCEDURE -aiCanonName (p: LONGINT): LONGINT "(LONGINT)((struct addrinfo*)p)->ai_canonname";
|
||||
PROCEDURE -aiNext (p: LONGINT): LONGINT "(LONGINT)((struct addrinfo*)p)->ai_next";
|
||||
|
||||
|
||||
PROCEDURE -caddrinfo(family, socktype, protocol, flags: LONGINT) "struct addrinfo ai={flags,family,socktype,protocol,0}";
|
||||
PROCEDURE -caddrinfoptr "struct addrinfo *pai";
|
||||
PROCEDURE -getaddrinfo(host, service: LONGINT): INTEGER
|
||||
"(INTEGER)getaddrinfo((char*)host, (char*)service, &ai, &pai)";
|
||||
PROCEDURE -pai(): LONGINT "(LONGINT)pai";
|
||||
PROCEDURE -freeaddrinfo(addrinfo: LONGINT) "freeaddrinfo((struct addrinfo*)addrinfo)";
|
||||
|
||||
|
||||
(* To get a local receiving address, past host as an empty string. *)
|
||||
PROCEDURE Lookup*(host, service: ARRAY OF CHAR; family, socktype: LONGINT; VAR addr: SocketAddress): Platform.ErrorCode;
|
||||
VAR addrinfo, hostptr, flags: LONGINT; result: Platform.ErrorCode;
|
||||
BEGIN
|
||||
IF host[0] = 0X THEN
|
||||
hostptr := 0; flags := AIPASSIVE();
|
||||
ELSE
|
||||
hostptr := SYSTEM.ADR(host); flags := 0;
|
||||
END;
|
||||
caddrinfo(family, socktype, 0, flags);
|
||||
caddrinfoptr;
|
||||
result := getaddrinfo(hostptr, SYSTEM.ADR(service));
|
||||
IF result = EAISYSTEM() THEN RETURN Platform.Error() END;
|
||||
(* Return getaddrinfo specific reslts as negative numbers to avoid clash with OS error codes. *)
|
||||
IF result # 0 THEN RETURN -ABS(result) END;
|
||||
|
||||
addrinfo := pai(); addr.length := aiAddrLen(addrinfo);
|
||||
IF (addrinfo = 0) OR (addr.length <= 0) THEN RETURN SHORT(-ABS(EAIFAIL())) END;
|
||||
|
||||
ASSERT(addr.length <= LEN(addr.buf));
|
||||
SYSTEM.MOVE(aiSockAddr(addrinfo), SYSTEM.ADR(addr.buf), addr.length);
|
||||
|
||||
freeaddrinfo(addrinfo);
|
||||
|
||||
RETURN result;
|
||||
END Lookup;
|
||||
|
||||
|
||||
|
||||
|
||||
PROCEDURE -socket(domain, type, protocol: LONGINT): LONGINT
|
||||
"(LONGINT)socket((int)domain, (int)type, (int)protocol)";
|
||||
|
||||
PROCEDURE Socket*(domain, type: LONGINT; VAR fd: LONGINT): Platform.ErrorCode;
|
||||
BEGIN
|
||||
fd := socket(domain, type, 0); (* No supported domain needs a non-zero protocol *)
|
||||
IF fd < 0 THEN RETURN Platform.Error() END;
|
||||
RETURN 0;
|
||||
END Socket;
|
||||
|
||||
|
||||
|
||||
|
||||
PROCEDURE -bind(sockfd: LONGINT; addr, addrlen: LONGINT): INTEGER
|
||||
"(INTEGER)bind((int)sockfd, (const struct sockaddr*)addr, (socklen_t)addrlen)";
|
||||
|
||||
PROCEDURE Bind*(sockfd: LONGINT; address: SocketAddress): Platform.ErrorCode;
|
||||
BEGIN
|
||||
IF bind(sockfd, SYSTEM.ADR(address.buf), address.length) < 0 THEN RETURN Platform.Error() END;
|
||||
RETURN 0;
|
||||
END Bind;
|
||||
|
||||
|
||||
|
||||
|
||||
PROCEDURE -listen(sockfd, backlog: LONGINT): INTEGER
|
||||
"(INTEGER)listen((int)sockfd, (int)backlog)";
|
||||
|
||||
PROCEDURE Listen*(sockfd, backlog: LONGINT): INTEGER;
|
||||
BEGIN RETURN listen(sockfd, backlog)
|
||||
END Listen;
|
||||
|
||||
|
||||
|
||||
|
||||
PROCEDURE -accept(sockfd: LONGINT; addr, addrlen: LONGINT): LONGINT
|
||||
"(LONGINT)accept((int)sockfd, (struct sockaddr*)addr, (socklen_t*)addrlen)";
|
||||
|
||||
PROCEDURE Accept*(sockfd: LONGINT; VAR address: SocketAddress; VAR newfd: LONGINT): Platform.ErrorCode;
|
||||
BEGIN
|
||||
address.length := LEN(address.buf);
|
||||
newfd := accept(sockfd, SYSTEM.ADR(address.buf), SYSTEM.ADR(address.length));
|
||||
IF newfd < 0 THEN RETURN Platform.Error() END;
|
||||
RETURN 0
|
||||
END Accept;
|
||||
|
||||
|
||||
|
||||
|
||||
PROCEDURE -connect(sockfd, addr, length: LONGINT): INTEGER
|
||||
"(INTEGER)connect((int)sockfd, (struct sockaddr*)addr, (socklen_t)length)";
|
||||
|
||||
PROCEDURE Connect*(sockfd: LONGINT; addr: SocketAddress): Platform.ErrorCode;
|
||||
BEGIN
|
||||
IF connect(sockfd, SYSTEM.ADR(addr.buf), addr.length) < 0 THEN RETURN Platform.Error() END;
|
||||
RETURN 0;
|
||||
END Connect;
|
||||
|
||||
|
||||
|
||||
|
||||
PROCEDURE -recvfrom(sockfd, buf, buflen, flags, saddr: LONGINT; socklen: LONGINT): INTEGER
|
||||
"(INTEGER)recvfrom((int)sockfd, (void*)buf, (size_t)buflen, (int)flags, (struct sockaddr*)saddr, (socklen_t*)socklen)";
|
||||
|
||||
PROCEDURE ReceiveFrom*(
|
||||
sockfd: LONGINT;
|
||||
VAR buf: ARRAY OF SYSTEM.BYTE; VAR length: LONGINT;
|
||||
flags: LONGINT;
|
||||
VAR sockaddr: SocketAddress
|
||||
): Platform.ErrorCode;
|
||||
BEGIN
|
||||
sockaddr.length := LEN(sockaddr.buf);
|
||||
length := recvfrom(
|
||||
sockfd,
|
||||
SYSTEM.ADR(buf), LEN(buf),
|
||||
flags,
|
||||
SYSTEM.ADR(sockaddr.buf), SYSTEM.ADR(sockaddr.length)
|
||||
);
|
||||
IF length < 0 THEN RETURN Platform.Error() END;
|
||||
RETURN 0;
|
||||
END ReceiveFrom;
|
||||
|
||||
|
||||
|
||||
PROCEDURE -sendto(sockfd, buf, len, flags, addr, addrlen: LONGINT): LONGINT
|
||||
"(LONGINT)sendto((int)sockfd, (void*)buf, (size_t)len, (int)flags, (struct sockaddr*)addr, (socklen_t)addrlen)";
|
||||
|
||||
PROCEDURE SendTo*(sockfd: LONGINT; VAR buf: ARRAY OF SYSTEM.BYTE; buflen, flags: LONGINT; addr: SocketAddress): Platform.ErrorCode;
|
||||
BEGIN
|
||||
IF sendto(sockfd, SYSTEM.ADR(buf), buflen, flags, SYSTEM.ADR(addr.buf), addr.length) < 0 THEN
|
||||
RETURN Platform.Error()
|
||||
ELSE
|
||||
RETURN 0
|
||||
END
|
||||
END SendTo;
|
||||
|
||||
|
||||
|
||||
|
||||
PROCEDURE -FDZERO(VAR fds: FDset) "FD_ZERO((fd_set*)fds)";
|
||||
PROCEDURE ZeroFDs*(VAR fds: FDset); BEGIN FDZERO(fds) END ZeroFDs;
|
||||
|
||||
PROCEDURE -FDCLR(i: LONGINT; VAR fds: FDset) "FD_CLR((int)i, (fd_set*)fds)";
|
||||
PROCEDURE ClearFD*(i: LONGINT; VAR fds: FDset); BEGIN FDCLR(i, fds) END ClearFD;
|
||||
|
||||
PROCEDURE -FDSET(i: LONGINT; VAR fds: FDset) "FD_SET((int)i, (fd_set*)fds)";
|
||||
PROCEDURE SetFD*(i: LONGINT; VAR fds: FDset); BEGIN FDSET(i, fds) END SetFD;
|
||||
|
||||
PROCEDURE -FDISSET(i: LONGINT; VAR fds: FDset): INTEGER "(INTEGER)FD_ISSET((int)i, (fd_set*)fds)";
|
||||
PROCEDURE FDisSet*(i: LONGINT; VAR fds: FDset): BOOLEAN;
|
||||
BEGIN RETURN FDISSET(i, fds) # 0 END FDisSet;
|
||||
|
||||
PROCEDURE -SizeofFdSet(): LONGINT "(LONGINT)sizeof(fd_set)";
|
||||
|
||||
|
||||
PROCEDURE -timeval(ms: LONGINT) "struct timeval tv = {ms/1000, (ms%1000)*1000}";
|
||||
PROCEDURE -select(socketLimit: LONGINT; VAR read, write, except: FDset): LONGINT
|
||||
"select((int)socketLimit, (fd_set*)read, (fd_set*)write, (fd_set*)except, &tv)";
|
||||
|
||||
PROCEDURE Select*(socketLimit: LONGINT; VAR read, write, except: FDset; ms: LONGINT; VAR readycount: LONGINT): Platform.ErrorCode;
|
||||
BEGIN
|
||||
timeval(ms);
|
||||
readycount := select(socketLimit, read, write, except);
|
||||
IF readycount < 0 THEN readycount := 0; RETURN Platform.Error() END;
|
||||
RETURN 0
|
||||
END Select;
|
||||
|
||||
|
||||
|
||||
|
||||
BEGIN
|
||||
ASSERT(SIZE(FDset) >= SizeofFdSet());
|
||||
v4 := AFINET();
|
||||
v6 := AFINET6();
|
||||
Stream := SOCKSTREAM();
|
||||
Datagram := SOCKDGRAM();
|
||||
END IP.
|
||||
219
src/tools/testcoordinator/TestClient.Mod
Normal file
219
src/tools/testcoordinator/TestClient.Mod
Normal file
|
|
@ -0,0 +1,219 @@
|
|||
MODULE TestClient;
|
||||
|
||||
IMPORT IP, Platform, Console, Strings, SYSTEM;
|
||||
|
||||
CONST
|
||||
ServerName = "gan.brownsmeet.com";
|
||||
ServerPort = "2055";
|
||||
|
||||
TYPE
|
||||
LineBuffer = RECORD
|
||||
text: ARRAY 4096 OF CHAR;
|
||||
length: INTEGER;
|
||||
CR: BOOLEAN
|
||||
END;
|
||||
|
||||
VAR
|
||||
Socket: Platform.FileHandle;
|
||||
Server: IP.SocketAddress;
|
||||
Param: ARRAY 1024 OF CHAR;
|
||||
Buffer: LineBuffer;
|
||||
|
||||
(* Console output convenience APIs *)
|
||||
|
||||
PROCEDURE cs(s: ARRAY OF CHAR);
|
||||
(* Oberon07 compatible variant of Console.String (LEN(s) safe). *)
|
||||
VAR i: LONGINT;
|
||||
BEGIN
|
||||
i := 0; WHILE (i<LEN(s)) & (s[i] # 0X) DO Console.Char(s[i]); INC(i) END
|
||||
END cs;
|
||||
|
||||
PROCEDURE ci (i,w: LONGINT); BEGIN Console.Int(i,w) END ci;
|
||||
PROCEDURE cl; BEGIN cs(Platform.nl) END cl;
|
||||
PROCEDURE csl(s: ARRAY OF CHAR); BEGIN cs(s); cl END csl;
|
||||
|
||||
|
||||
|
||||
|
||||
PROCEDURE ErrorCheck(err: Platform.ErrorCode; msg: ARRAY OF CHAR);
|
||||
BEGIN
|
||||
IF err # 0 THEN
|
||||
csl("exit;");
|
||||
cs(msg); ci(err,1); cl; HALT(1);
|
||||
END
|
||||
END ErrorCheck;
|
||||
|
||||
|
||||
(* Line buffer output APIs *)
|
||||
|
||||
PROCEDURE InitBuffer;
|
||||
BEGIN
|
||||
Buffer.text := '';
|
||||
Buffer.length := 0;
|
||||
Buffer.CR := FALSE;
|
||||
END InitBuffer;
|
||||
|
||||
PROCEDURE AddChar(c: CHAR);
|
||||
BEGIN IF Buffer.length < LEN(Buffer.text) THEN Buffer.text[Buffer.length] := c; INC(Buffer.length) END
|
||||
END AddChar;
|
||||
|
||||
PROCEDURE AddString(s: ARRAY OF CHAR);
|
||||
VAR i: LONGINT;
|
||||
BEGIN i := 0;
|
||||
WHILE (Buffer.length < LEN(Buffer.text)) & (i < LEN(s)) & (s[i] # 0X) DO
|
||||
Buffer.text[Buffer.length] := s[i];
|
||||
INC(Buffer.length);
|
||||
INC(i)
|
||||
END
|
||||
END AddString;
|
||||
|
||||
PROCEDURE FlushLine;
|
||||
VAR i: INTEGER;
|
||||
BEGIN
|
||||
AddChar(0AX); Buffer.text[LEN(Buffer.text)-1] := 0AX; (* Force EOLN even on overflow *)
|
||||
ErrorCheck(Platform.Write(Socket, SYSTEM.ADR(Buffer.text), Buffer.length), "Failed to write log to network: ");
|
||||
ErrorCheck(Platform.Write(Platform.StdOut, SYSTEM.ADR(Buffer.text), Buffer.length), "Failed to write log to stdout: ");
|
||||
InitBuffer
|
||||
END FlushLine;
|
||||
|
||||
PROCEDURE TwoDigits(i: LONGINT);
|
||||
BEGIN AddChar(CHR(48 + i DIV 10 MOD 10)); AddChar(CHR(48 + i MOD 10));
|
||||
END TwoDigits;
|
||||
|
||||
PROCEDURE Timestamp;
|
||||
VAR t, d: LONGINT;
|
||||
BEGIN
|
||||
AddString(Param); AddChar(' ');
|
||||
Platform.GetClock(t,d);
|
||||
TwoDigits(ASH(t, -12)); AddChar('.');
|
||||
TwoDigits(ASH(t, -6) MOD 64); AddChar('.');
|
||||
TwoDigits(t MOD 64); AddString(': ');
|
||||
END Timestamp;
|
||||
|
||||
PROCEDURE LogCharacter(c: CHAR);
|
||||
BEGIN
|
||||
IF Buffer.length = 0 THEN Timestamp END;
|
||||
IF Buffer.CR OR (c = 0AX) THEN FlushLine END;
|
||||
CASE c OF
|
||||
0DX: Buffer.CR := TRUE
|
||||
| 0AX:
|
||||
ELSE AddChar(c)
|
||||
END
|
||||
END LogCharacter;
|
||||
|
||||
PROCEDURE FlushLog;
|
||||
BEGIN IF (Buffer.length # 0) OR Buffer.CR THEN FlushLine END
|
||||
END FlushLog;
|
||||
|
||||
|
||||
(* Debugging ... *)
|
||||
PROCEDURE ec(c: CHAR); VAR err: Platform.ErrorCode;
|
||||
BEGIN err := Platform.Write(Platform.StdErr, SYSTEM.ADR(c), 1) END ec;
|
||||
PROCEDURE es(s: ARRAY OF CHAR); VAR i: INTEGER;
|
||||
BEGIN i := 0; WHILE (i < LEN(s)) & (s[i] # 0X) DO ec(s[i]); INC(i) END END es;
|
||||
PROCEDURE esl(s: ARRAY OF CHAR); BEGIN es(s); es(Platform.nl) END esl;
|
||||
PROCEDURE eu(l: LONGINT); (* Unsigned (i.e. positive) integer *)
|
||||
BEGIN IF l>10 THEN eu(l DIV 10) END; ec(CHR(ORD('0') + (l MOD 10))) END eu;
|
||||
PROCEDURE ei(l: LONGINT);
|
||||
BEGIN IF l<0 THEN ec('-'); l := -l END; eu(l) END ei;
|
||||
|
||||
|
||||
|
||||
PROCEDURE ConnectSocket;
|
||||
VAR err: Platform.ErrorCode;
|
||||
BEGIN
|
||||
err := IP.Connect(Socket, Server);
|
||||
WHILE Platform.ConnectionFailed(err) OR Platform.TimedOut(err) DO
|
||||
es("Waiting for coordinator, error code: "); ei(err); esl(".");
|
||||
Platform.Delay(30000);
|
||||
err := IP.Connect(Socket, Server);
|
||||
END;
|
||||
ErrorCheck(err, "Couldn't connect to server: ");
|
||||
END ConnectSocket;
|
||||
|
||||
|
||||
PROCEDURE LogStdIn;
|
||||
VAR i, n: LONGINT; inbuf: ARRAY 8192 OF CHAR;
|
||||
BEGIN
|
||||
ConnectSocket;
|
||||
ErrorCheck(Platform.ReadBuf(Platform.StdIn, inbuf, n), "Failure reading standard input: ");
|
||||
InitBuffer;
|
||||
WHILE n > 0 DO
|
||||
i := 0;
|
||||
WHILE i < n DO LogCharacter(inbuf[i]); INC(i) END;
|
||||
ErrorCheck(Platform.ReadBuf(Platform.StdIn, inbuf, n), "Failure reading standard input: ");
|
||||
END;
|
||||
FlushLog;
|
||||
END LogStdIn;
|
||||
|
||||
|
||||
PROCEDURE SendString(s: ARRAY OF CHAR);
|
||||
BEGIN
|
||||
ErrorCheck(Platform.Write(Socket, SYSTEM.ADR(s), Strings.Length(s)),
|
||||
"Failed to write string to socket: ");
|
||||
END SendString;
|
||||
|
||||
|
||||
PROCEDURE SendStrings(s1, s2: ARRAY OF CHAR);
|
||||
VAR buf: ARRAY 4096 OF CHAR;
|
||||
BEGIN COPY(s1, buf); Strings.Append(s2, buf); SendString(buf)
|
||||
END SendStrings;
|
||||
|
||||
|
||||
PROCEDURE Continue;
|
||||
BEGIN ConnectSocket; SendStrings("-continue ", Param)
|
||||
END Continue;
|
||||
|
||||
|
||||
PROCEDURE Wait;
|
||||
VAR buf: ARRAY 64 OF CHAR; n: LONGINT; err: Platform.ErrorCode; waiting: BOOLEAN;
|
||||
BEGIN
|
||||
waiting := TRUE;
|
||||
WHILE waiting DO
|
||||
ConnectSocket; SendStrings("-wait ", Param);
|
||||
ErrorCheck(Platform.ReadBuf(Socket, buf, n), "Failed to read command from test coordinator: ");
|
||||
waiting := n <= 0 (* n=0 => coordinator was terminated *)
|
||||
END;
|
||||
IF n < LEN(buf) THEN buf[n] := 0X END;
|
||||
es("Received command: '"); es(buf); esl("'.");
|
||||
csl(buf);
|
||||
IF buf = "exit" THEN Platform.Exit(1) END
|
||||
END Wait;
|
||||
|
||||
|
||||
PROCEDURE Help;
|
||||
BEGIN
|
||||
cl;
|
||||
csl("TestClient - test log client"); cl;
|
||||
csl("usage:"); cl;
|
||||
csl(" command | TestClient -s id - Send command output identified by id.");
|
||||
csl(" TestClient -w id - wait until TestClient -c runs somewhere.");
|
||||
csl(" TestClient -c - continue all pending TestClient -w commands.");
|
||||
Platform.Exit(0);
|
||||
END Help;
|
||||
|
||||
|
||||
PROCEDURE ParseParameters;
|
||||
VAR option: ARRAY 1024 OF CHAR;
|
||||
BEGIN
|
||||
IF Platform.ArgCount > 1 THEN Platform.GetArg(1, option) END;
|
||||
IF Platform.ArgCount = 3 THEN Platform.GetArg(2, Param) END;
|
||||
|
||||
IF (Platform.ArgCount = 3) & (option = "-w") THEN Wait
|
||||
ELSIF (Platform.ArgCount = 3) & (option = "-c") THEN Continue
|
||||
ELSIF (Platform.ArgCount = 3) & (option = "-s") THEN LogStdIn
|
||||
ELSE Help
|
||||
END
|
||||
END ParseParameters;
|
||||
|
||||
|
||||
|
||||
|
||||
BEGIN
|
||||
ErrorCheck(IP.Socket(IP.v4, IP.Stream, Socket), "Couldn't create sender socket: ");
|
||||
ErrorCheck(IP.Lookup(ServerName, ServerPort, IP.v4, IP.Stream, Server),
|
||||
"Couldn't lookup server socket address: ");
|
||||
ParseParameters;
|
||||
ErrorCheck(Platform.Close(Socket), "Couldn't close socket: ")
|
||||
END TestClient.
|
||||
|
||||
270
src/tools/testcoordinator/TestCoordinator.Mod
Normal file
270
src/tools/testcoordinator/TestCoordinator.Mod
Normal file
|
|
@ -0,0 +1,270 @@
|
|||
MODULE TestCoordinator;
|
||||
|
||||
(*
|
||||
Listens for client test machines, telling them when to start tests and recording
|
||||
status and log data that they send.
|
||||
Also listens to command machine that says when to start a new set of tests.
|
||||
*)
|
||||
|
||||
IMPORT IP, Platform, SYSTEM, Console, Strings;
|
||||
|
||||
CONST
|
||||
ListenPort = "2055";
|
||||
CoIdle = 0;
|
||||
CoConnected = 1;
|
||||
CoUnderway = 2;
|
||||
CoWaiting = 3;
|
||||
|
||||
TYPE
|
||||
Connection = POINTER TO ConnectionState;
|
||||
ConnectionState = RECORD
|
||||
fd: LONGINT; (* Socket descriptor *)
|
||||
state: INTEGER; (* CoIdle / CoConnected / CoWaiting *)
|
||||
file: Platform.FileHandle;
|
||||
text: ARRAY 4096 OF CHAR;
|
||||
length: INTEGER;
|
||||
CR: BOOLEAN;
|
||||
END;
|
||||
|
||||
VAR
|
||||
MaxSocket: LONGINT;
|
||||
Listener: LONGINT;
|
||||
Connections: ARRAY IP.FDcount OF Connection;
|
||||
|
||||
|
||||
(* Console output convenience APIs *)
|
||||
|
||||
PROCEDURE cs (s: ARRAY OF CHAR);
|
||||
(* Oberon07 compatible variant of Console.String (LEN(s) safe). *)
|
||||
VAR i: LONGINT;
|
||||
BEGIN
|
||||
i := 0; WHILE (i<LEN(s)) & (s[i] # 0X) DO Console.Char(s[i]); INC(i) END;
|
||||
END cs;
|
||||
|
||||
PROCEDURE ci(i,w: LONGINT); BEGIN Console.Int(i,w) END ci;
|
||||
PROCEDURE ch(i: LONGINT); BEGIN Console.Hex(i) END ch;
|
||||
PROCEDURE cc(c: CHAR); BEGIN Console.Char(c) END cc;
|
||||
PROCEDURE cl; BEGIN cs(Platform.nl) END cl;
|
||||
PROCEDURE csl(s: ARRAY OF CHAR); BEGIN cs(s); cl END csl;
|
||||
|
||||
|
||||
PROCEDURE ErrorCheck(err: Platform.ErrorCode; msg: ARRAY OF CHAR);
|
||||
(* OS API wrapper for when no error is expected. *)
|
||||
BEGIN IF err # 0 THEN cs(msg); ci(err,1); cl; HALT(1) END
|
||||
END ErrorCheck;
|
||||
|
||||
|
||||
(* Connection management APIs *)
|
||||
|
||||
PROCEDURE InitConnection(fd: LONGINT);
|
||||
VAR co: Connection;
|
||||
BEGIN
|
||||
IF Connections[fd] = NIL THEN NEW(Connections[fd]) END;
|
||||
co := Connections[fd];
|
||||
co.fd := fd;
|
||||
co.state := CoConnected;
|
||||
co.file := 0;
|
||||
co.text := '';
|
||||
co.length := 0;
|
||||
co.CR := FALSE;
|
||||
END InitConnection;
|
||||
|
||||
PROCEDURE OpenLogFile(co: Connection);
|
||||
VAR filename: ARRAY 1024 OF CHAR; i: INTEGER;
|
||||
BEGIN
|
||||
ASSERT(co.file = 0);
|
||||
i := 0;
|
||||
WHILE (i < LEN(co.text)) & (i < LEN(filename)-1) & (co.text[i] # ' ') & (co.text[i] # 0X) DO
|
||||
filename[i] := co.text[i]; INC(i);
|
||||
END;
|
||||
IF i = 0 THEN filename := "unnamed" ELSE filename[i] := 0X END;
|
||||
cs("Connected to "); cs(filename); cs(" build on fd "); ci(co.fd,1); csl(".");
|
||||
Strings.Append(".log", filename);
|
||||
IF Platform.Absent(Platform.OldRW(filename, co.file)) THEN
|
||||
ErrorCheck(Platform.New(filename, co.file), "Couldn't create log file: ")
|
||||
ELSE
|
||||
ErrorCheck(Platform.Seek(co.file, 0, Platform.SeekEnd), "Couldn't position exisiting log file at end: ")
|
||||
END;
|
||||
END OpenLogFile;
|
||||
|
||||
PROCEDURE FlushLine(co: Connection);
|
||||
BEGIN
|
||||
IF co.file = 0 THEN OpenLogFile(co) END;
|
||||
ErrorCheck(Platform.Write(co.file, SYSTEM.ADR(co.text), co.length), "Failed to write to log file: ");
|
||||
ErrorCheck(Platform.Write(co.file, SYSTEM.ADR(Platform.nl), Strings.Length(Platform.nl)), "Failed to write to log file: ");
|
||||
co.length := 0;
|
||||
co.CR := FALSE;
|
||||
END FlushLine;
|
||||
|
||||
PROCEDURE lc(co: Connection; c: CHAR);
|
||||
BEGIN
|
||||
(* IF (co.length = 0) & ~co.CR THEN <do something at start of line time> END; *)
|
||||
IF co.CR OR (c = 0AX) THEN FlushLine(co) END;
|
||||
CASE c OF
|
||||
0DX: co.CR := TRUE
|
||||
| 0AX:
|
||||
ELSE co.text[co.length] := c; INC(co.length)
|
||||
END
|
||||
END lc;
|
||||
|
||||
PROCEDURE ls(co: Connection; s: ARRAY OF CHAR);
|
||||
VAR i: LONGINT;
|
||||
BEGIN i := 0; WHILE (i < LEN(s)) & (s[i] # 0X) DO lc(co, s[i]); INC(i) END
|
||||
END ls;
|
||||
|
||||
|
||||
|
||||
|
||||
PROCEDURE AcceptConnection;
|
||||
VAR
|
||||
Them: IP.SocketAddress;
|
||||
fd: LONGINT;
|
||||
BEGIN
|
||||
ErrorCheck(IP.Accept(Listener, Them, fd), "Accept failed: ");
|
||||
IF fd > MaxSocket THEN MaxSocket := fd END;
|
||||
InitConnection(fd);
|
||||
(* TODO: Set fd as non-blocking: O_NONBLOCK and fcntl(). *)
|
||||
END AcceptConnection;
|
||||
|
||||
|
||||
PROCEDURE Continue(co: Connection; param: ARRAY OF CHAR);
|
||||
VAR msg: ARRAY 10 OF CHAR; err: Platform.ErrorCode;
|
||||
BEGIN
|
||||
cs("Starting fd "); ci(co.fd,1); cl;
|
||||
msg := "Go.";
|
||||
ErrorCheck(Platform.Write(co.fd, SYSTEM.ADR(param), Strings.Length(param)), "Couldn't send continue message: ");
|
||||
ErrorCheck(Platform.Close(co.fd), "Couldn't close waiting socket: ");
|
||||
co.fd := 0;
|
||||
co.state := CoIdle;
|
||||
END Continue;
|
||||
|
||||
|
||||
PROCEDURE ParseWord(buf: ARRAY OF CHAR; VAR i: INTEGER; VAR word: ARRAY OF CHAR);
|
||||
VAR j: INTEGER;
|
||||
BEGIN
|
||||
END ParseWord;
|
||||
|
||||
|
||||
PROCEDURE Command(co: Connection; buf: ARRAY OF CHAR);
|
||||
VAR cmd, param: ARRAY 1024 OF CHAR; i,j: INTEGER;
|
||||
BEGIN
|
||||
i := 0;
|
||||
(* The command is everything up to the first space *)
|
||||
WHILE (i<LEN(buf)) & (buf[i] = ' ') DO INC(i) END;
|
||||
j := 0;
|
||||
WHILE (i<LEN(buf)) & (j<LEN(cmd)) & (ORD(buf[i]) > 32) DO
|
||||
cmd[j] := buf[i]; INC(i); INC(j)
|
||||
END;
|
||||
IF j < LEN(cmd) THEN cmd[j] := 0X END;
|
||||
|
||||
(* The parameter is everything else (except leading spaces). *)
|
||||
WHILE (i<LEN(buf)) & (buf[i] = ' ') DO INC(i) END;
|
||||
j := 0;
|
||||
WHILE (i<LEN(buf)) & (j<LEN(param)) & (buf[i] # 0X) DO
|
||||
param[j] := buf[i]; INC(i); INC(j)
|
||||
END;
|
||||
IF j < LEN(param) THEN param[j] := 0X END;
|
||||
|
||||
IF cmd = "-wait" THEN
|
||||
co.state := CoWaiting; cs(param); cs(" waiting on fd "); ci(co.fd,1); csl(".");
|
||||
ELSIF cmd = "-continue" THEN
|
||||
i := 0;
|
||||
WHILE i < MaxSocket DO
|
||||
IF (Connections[i] # NIL) & (Connections[i].state = CoWaiting) THEN
|
||||
Continue(Connections[i], param)
|
||||
END;
|
||||
INC(i)
|
||||
END
|
||||
ELSE
|
||||
ls(co, buf)
|
||||
END
|
||||
END Command;
|
||||
|
||||
PROCEDURE DataReceived(co: Connection; VAR buf: ARRAY OF CHAR; n: LONGINT);
|
||||
BEGIN
|
||||
IF co # NIL THEN
|
||||
IF n < LEN(buf) THEN buf[n] := 0X END;
|
||||
IF (co.state = CoConnected) & (buf[0] = '-') THEN
|
||||
Command(co, buf)
|
||||
ELSE
|
||||
co.state := CoUnderway; ls(co, buf)
|
||||
END
|
||||
END
|
||||
END DataReceived;
|
||||
|
||||
|
||||
PROCEDURE ConnectionClosed(co: Connection);
|
||||
BEGIN
|
||||
IF co # NIL THEN
|
||||
IF co.state = CoWaiting THEN cs("fd "); ci(co.fd,1); csl(" closed.") END;
|
||||
ErrorCheck(Platform.Close(co.fd), "Failed to close connection: ");
|
||||
co.fd := 0;
|
||||
IF co.length > 0 THEN FlushLine(co) END;
|
||||
IF co.file # 0 THEN
|
||||
ErrorCheck(Platform.Close(co.file), "Failed to close connection log file: ");
|
||||
END;
|
||||
co.state := CoIdle;
|
||||
co.file := 0;
|
||||
END
|
||||
END ConnectionClosed;
|
||||
|
||||
|
||||
PROCEDURE Cycle;
|
||||
VAR
|
||||
Us: IP.SocketAddress;
|
||||
err: Platform.ErrorCode;
|
||||
n: LONGINT;
|
||||
rbuf: ARRAY 4100 OF CHAR;
|
||||
i: LONGINT;
|
||||
waitcount: LONGINT;
|
||||
readFDs: IP.FDset;
|
||||
noFDs: IP.FDset;
|
||||
co: Connection;
|
||||
BEGIN
|
||||
IP.ZeroFDs(noFDs);
|
||||
|
||||
ErrorCheck(IP.Socket(IP.v4, IP.Stream, Listener), "Couldn't create listener socket: ");
|
||||
ErrorCheck(IP.Lookup("", ListenPort, IP.v4, IP.Stream, Us), "Couldn't lookup our own socket address: ");
|
||||
ErrorCheck(IP.Bind (Listener, Us), "Bind failed: ");
|
||||
ErrorCheck(IP.Listen(Listener, 10), "Listen failed: ");
|
||||
|
||||
csl("Test coordinator listening for test clients.");
|
||||
|
||||
MaxSocket := Listener;
|
||||
LOOP
|
||||
(* Prepare select parameters *)
|
||||
IP.ZeroFDs(readFDs);
|
||||
IP.SetFD(Listener, readFDs);
|
||||
i := 0; WHILE i <= MaxSocket DO
|
||||
co := Connections[i];
|
||||
IF (co # NIL) & (co.state >= CoConnected) THEN IP.SetFD(i, readFDs) END;
|
||||
INC(i) END;
|
||||
|
||||
(* Wait for some fd to need servicing, or 60 seconds. *)
|
||||
ErrorCheck(IP.Select(MaxSocket+1, readFDs, noFDs, noFDs, 60000, waitcount), "Wait for next service activity failed: ");
|
||||
IF waitcount > 0 THEN
|
||||
i := 0;
|
||||
WHILE i <= MaxSocket DO
|
||||
IF IP.FDisSet(i, readFDs) THEN
|
||||
IF i = Listener THEN
|
||||
AcceptConnection;
|
||||
ELSE
|
||||
ErrorCheck(Platform.ReadBuf(i, rbuf, n), "ReadBuf failed: ");
|
||||
IF n = 0 THEN
|
||||
ConnectionClosed(Connections[i]); (* Client has closed the connection in an orderly manner. *)
|
||||
ELSE
|
||||
DataReceived(Connections[i], rbuf, n)
|
||||
END
|
||||
END
|
||||
END;
|
||||
INC(i)
|
||||
END
|
||||
END
|
||||
END;
|
||||
err := Platform.Close(Listener)
|
||||
END Cycle;
|
||||
|
||||
BEGIN
|
||||
Cycle;
|
||||
END TestCoordinator.
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue