{
Summary:
Windows copyover controller
## $Id: copyover.dpr,v 1.8 2004/04/12 20:49:02 druid Exp $
}
program copyover;
{$APPTYPE CONSOLE}
{$IFDEF WIN32}
uses
SysUtils,
DateUtils,
Classes,
Windows,
WinSock2,
debug,
console,
socket;
const
pipeName : pchar = '\\.\pipe\grendel';
type
Connection = class
socket : TSocket;
name : string;
end;
GConsoleCopyover = class(GConsoleWriter)
public
procedure write(timestamp : integer; const text : string; debugLevel : integer = 0); override;
end;
var
prot : TWSAProtocol_Info;
pipe : THandle;
connectionList : TList;
a, w, len : cardinal;
g : array[0..1023] of char;
suc : boolean;
sock : TSocket;
c : Connection;
SI: TStartupInfo;
PI: TProcessInformation;
f : file;
ret : integer;
cons : GConsole;
calling_pid : cardinal;
hProcess : THandle;
exitCode : cardinal;
procedure GConsoleCopyover.write(timestamp : integer; const text : string; debugLevel : integer = 0);
begin
writeln('[' + FormatDateTime('hh:nn:ss', UnixToDateTime(timestamp)) + '] ', text);
end;
begin
cons := GConsole.Create();
cons.attachWriter(GConsoleLogWriter.Create('copyover'));
cons.attachWriter(GConsoleCopyover.Create());
initDebug();
connectionList := TList.Create();
cons.write('Starting copyover...');
pipe := INVALID_HANDLE_VALUE;
while (true) do
begin
pipe := CreateFile(pipeName, GENERIC_READ or GENERIC_WRITE, 0, nil, OPEN_EXISTING, 0, 0);
if (pipe <> INVALID_HANDLE_VALUE) then
break;
ret := GetLastError();
if (ret <> ERROR_PIPE_BUSY) and (ret <> ERROR_FILE_NOT_FOUND) then
exit;
// All pipe instances are busy, so wait a second
if (ret = ERROR_PIPE_BUSY) then
if (not WaitNamedPipe(pipeName, 500)) then
exit;
end;
sock := -1;
suc := ReadFile(pipe, calling_pid, 4, w, nil);
repeat
suc := ReadFile(pipe, prot, sizeof(prot), w, nil);
if (not suc) or (w < sizeof(prot)) then
break;
if (suc) then
sock := WSASocket(prot.iAddressFamily, SOCK_STREAM, IPPROTO_IP, @prot, 0, 0);
suc := ReadFile(pipe, len, 4, w, nil);
if (not suc) or (w < 4) then
break;
suc := ReadFile(pipe, g, len, w, nil);
if (not suc) or (w < len) then
break;
if (suc) and (sock <> -1) then
begin
g[len] := #0;
c := Connection.Create;
c.socket := sock;
c.name := g;
connectionList.add(c);
end;
until (not suc);
CloseHandle(pipe);
// wait for calling Grendel process to die
cons.write('Waiting for calling process #' + IntToStr(calling_pid) + ' to die...');
hProcess := OpenProcess(PROCESS_QUERY_INFORMATION, false, calling_pid);
GetExitCodeProcess(hProcess, exitCode);
while (exitCode = STILL_ACTIVE) do
begin
Sleep(25);
GetExitCodeProcess(hProcess, exitCode);
end;
CloseHandle(hProcess);
// check for any new grendel.exe in dir "bin\"
if (FileExists('bin\grendel.exe')) then
begin
if (CopyFile('bin\grendel.exe', 'grendel.exe', false)) then
begin
assign(f, 'bin\grendel.exe');
erase(f);
end;
end;
// check for a new core.bpl in dir "bin\"
if (FileExists('bin\core.bpl')) then
begin
if (CopyFile('bin\core.bpl', 'core.bpl', false)) then
begin
assign(f, 'bin\core.bpl');
erase(f);
end;
end;
strpcopy(g, #13#10'In the void of space, you look around... fragments of memory flash by...'#13#10);
if (connectionList.Count > 0) then
begin
for w := 0 to connectionList.Count - 1 do
begin
c := connectionList.items[w];
send(c.socket, g, strlen(g), 0);
end;
end;
sleep(1000);
cons.write('Spawning new process...');
FillChar(SI, SizeOf(SI), 0);
SI.cb := SizeOf(SI);
SI.wShowWindow := sw_show;
if (not CreateProcess('grendel.exe', 'grendel copyover', Nil, Nil, False, NORMAL_PRIORITY_CLASS or CREATE_NEW_CONSOLE, Nil, Nil, SI, PI)) then
exit;
pipe := CreateNamedPipe(pipeName, PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE or PIPE_READMODE_BYTE, 1, 0, 0, 10000, nil);
if (not ConnectNamedPipe(pipe, nil)) then
exit;
cons.write('Duplicating connections...');
if (connectionList.Count > 0) then
begin
for a := 0 to connectionList.Count - 1 do
begin
c := connectionList.items[a];
if (WSADuplicateSocket(c.socket, PI.dwProcessId, @prot) = -1) then
exit;
if (not WriteFile(pipe, prot, sizeof(prot), w, nil)) then
exit;
strpcopy(g, c.name);
len := strlen(g);
if (not WriteFile(pipe, len, 4, w, nil)) then
exit;
if (not WriteFile(pipe, g, len, w, nil)) then
exit;
closesocket(c.socket);
end;
end;
CloseHandle(pipe);
cons.write('Cleaned up.');
cons.Free();
end.
{$ENDIF}
{$IFDEF LINUX}
begin
writeln('Not implemented for this platform.');
end.
{$ENDIF}