255 lines
7.6 KiB
Plaintext
255 lines
7.6 KiB
Plaintext
{$X+,V-,B-,I-}
|
|
program Fsend; { Master / Sender }
|
|
|
|
{ Testprogram for the nwPEP unit / NwTP 0.6 API. (c) 1993,1995, R.Spronk }
|
|
|
|
{$DEFINE noTRACE}
|
|
|
|
uses dos,crt,nwMisc,nwBindry,nwConn,nwIPX,nwPEP;
|
|
|
|
CONST IOSocket=$5678; { socket to transmit/receive on }
|
|
|
|
Var ListenECB :Tecb; { ECB and header, to listen for acknowledgement }
|
|
ListenPepHdr :TpepHeader;
|
|
|
|
SendECB :Tecb; { ECB and header, used to send the data }
|
|
SendPepHdr :TpepHeader;
|
|
|
|
socket :word;
|
|
|
|
SendDataBuffer :array[1..546] of byte; { SendDataBufferfer for data to be sent }
|
|
|
|
ListenDataBuffer:array[1..8] of byte;
|
|
|
|
AckReceived :boolean; { set to true within the ListenForAckESR }
|
|
|
|
SendTransId :LongInt; { transactionID. This uniquely identifies
|
|
the packet. The slave/receiver has to
|
|
reply with the same transactionID in the
|
|
header of the acknowledgement. Only if
|
|
this number is the same as the transactioID
|
|
of the sent packet, the pavket is considered
|
|
successfully delivered. }
|
|
|
|
NewStack:array[1..1024] of word; { !! used by ESR }
|
|
StackBottom:word; { !! used by ESR }
|
|
|
|
f:file;
|
|
|
|
|
|
Procedure CheckError(err:boolean; errNbr:word);
|
|
begin
|
|
if err
|
|
then begin
|
|
writeln;
|
|
CASE errNbr of
|
|
$0100:writeln('IPX needs to be installed.');
|
|
$0200:writeln('Error: can''t locate the spcified username.');
|
|
$0201:begin
|
|
writeln('The specified user has multiple connections.');
|
|
writeln('This demonstation program doesn''t support multiple connections.');
|
|
end;
|
|
$0202:writeln('Error: can''t find the address of the supplied username.');
|
|
$0204:writeln('Transfer aborted after 50 retries.');
|
|
$0205:writeln('Key pressed: Transfer aborted.');
|
|
$0206:writeln('The supplied file couldn''t be found. Please supply full path.');
|
|
$0300:writeln('Error reading file.');
|
|
$10FE:writeln('Error opening socket: Socket Table Is Full.');
|
|
$10FF:writeln('Error opening socket: Socket is already open.');
|
|
end; {case}
|
|
IPXcloseSocket(IOsocket);
|
|
close(f);
|
|
halt(1);
|
|
end;
|
|
end;
|
|
|
|
Function TimeOut(t1,t2:word;n:byte):boolean;
|
|
{ ticks t2 - ticks t1 > n seconds ? }
|
|
Var lt1,lt2:LongInt;
|
|
begin
|
|
lt2:=t2;
|
|
if t1>t2 then lt2:=lt2+$FFFF;
|
|
TimeOut:=(lt2-t1)>(n*18);
|
|
end;
|
|
|
|
|
|
{$F+}
|
|
Procedure ListenForAckHandler(Var p:TPecb);
|
|
{ Interrupts are turned off -and should remain turned off- }
|
|
begin
|
|
IF (ListenECB.CompletionCode<>0) { packet must be suucessfully received.. }
|
|
or (ListenPepHdr.IPXhdr.packetType<>PEP_PACKET_TYPE) { of type PEP.. }
|
|
or (ListenPepHdr.ClientType<>$EA) { of client type $EA }
|
|
or (ListenPepHdr.TransactionID<>SendTransId) { with a correct clientID (of the packet the master sent) }
|
|
then IPXListenForPacket(ListenECB) { Invalid packet => listen again }
|
|
else AckReceived:=true; { valid packet => ACK received ! }
|
|
end;
|
|
{$F-}
|
|
|
|
{$F+}
|
|
Procedure ListenForAckESR; assembler;
|
|
asm { ES:SI are the only valid registers when entering this procedure ! }
|
|
{ interrupts are turned off -and should remain turned off- }
|
|
mov dx, seg stackbottom
|
|
mov ds, dx
|
|
|
|
mov dx,ss { setup of a new local stack }
|
|
mov bx,sp { ss:sp copied to dx:bx}
|
|
mov ax,ds
|
|
mov ss,ax
|
|
mov sp,offset stackbottom
|
|
push dx { push old ss:sp on new stack }
|
|
push bx
|
|
|
|
push es { push es:si on stack as local vars }
|
|
push si
|
|
mov di,sp
|
|
|
|
push ss { push address of local ptr on stack }
|
|
push di
|
|
CALL ListenForAckHandler
|
|
|
|
add sp,4 { skip stack ptr-copy }
|
|
pop bx { restore ss:sp from new stack }
|
|
pop dx
|
|
mov sp,bx
|
|
mov ss,dx
|
|
end;
|
|
{$F-}
|
|
|
|
|
|
Var dest:TinternetworkAddress;
|
|
ticks,ticks2:word;
|
|
retries :word;
|
|
|
|
Uname,Fname:string;
|
|
NbrOfConn:byte;
|
|
connList:TconnectionList;
|
|
|
|
p:byte;
|
|
FileInfo:searchrec;
|
|
FileSize:LongInt;
|
|
BytesRead:word;
|
|
|
|
TransferStartTicks,TransferEndTicks:word;
|
|
OriginalFileSize:LongInt;
|
|
|
|
begin
|
|
If paramcount<>2
|
|
then begin
|
|
writeln('Usage: FSEND <username> <filename>');
|
|
writeln('-The file will be sent to the workstation of the supplied username.');
|
|
writeln('-Run FGET on that workstation to receive the file.');
|
|
halt(1);
|
|
end;
|
|
Uname:=ParamStr(1);
|
|
UpString(Uname);
|
|
NbrOfConn:=0;
|
|
GetObjectConnectionNumbers(Uname,OT_USER,NbrOfConn,connList);
|
|
CheckError((nwConn.result>0) or (NbrOfConn=0),$200);
|
|
CheckError(NbrOfConn>1,$0201);
|
|
|
|
GetInternetAddress(connList[1],dest);
|
|
CheckError(nwconn.result>0,$0202);
|
|
dest.socket:=IOsocket;
|
|
|
|
Fname:=ParamStr(2);
|
|
Assign(f,Fname);
|
|
Reset(f,1);
|
|
CheckError(IOresult<>0,$0206);
|
|
|
|
|
|
IpxInitialize;
|
|
CheckError(nwIPX.result>0,$0100);
|
|
|
|
socket:=IOSocket;
|
|
IPXopenSocket(Socket,SHORT_LIVED_SOCKET);
|
|
CheckError(nwIPX.result>0,$1000+nwIPX.result);
|
|
|
|
{ setup listening for ack }
|
|
AckReceived:=False;
|
|
|
|
PEPsetupListenECB(Addr(ListenForAckESR),IOsocket,@ListenDataBuffer,8,
|
|
ListenPepHdr,ListenECB);
|
|
IPXListenForPacket(ListenECB);
|
|
|
|
{ send initial packet with the name and size of the file to be sent. }
|
|
findfirst(Fname,$FF,FileInfo);
|
|
Move(FileInfo.size,SendDataBuffer[16],4);
|
|
FileSize:=Fileinfo.size;
|
|
p:=length(Fname);
|
|
while (p>0) and (Fname[p]<>':') and (Fname[p]<>'\')
|
|
do dec(p);
|
|
If p>0
|
|
then delete (Fname,1,p);
|
|
Move(Fname[0],SendDataBuffer[1],15);
|
|
|
|
PEPsetupSendECB(NIL,IOsocket,dest,@SendDataBuffer[1],512,
|
|
SendPepHdr,SendECB);
|
|
SendTransID:=1;
|
|
SendPepHdr.ClientType:=$EA;
|
|
|
|
OriginalFileSize:=FileSize;
|
|
FileSize:=FileSize+512; { compensate length for information header }
|
|
|
|
writeln('FSEND waiting for remote handshake. (any key to abort)');
|
|
|
|
While Filesize>0
|
|
do begin
|
|
ackreceived:=false;
|
|
SendPepHdr.TransactionId:=SendTransId;
|
|
IPXsendPacket(SendECB);
|
|
{$IFDEF TRACE}
|
|
write('Packet#',SendTransID,' sent.');
|
|
{$ENDIF}
|
|
while sendECB.InuseFlag<>0
|
|
do IPXrelinquishControl;
|
|
|
|
IPXGetIntervalMarker(ticks);
|
|
retries:=0;
|
|
REPEAT
|
|
IPXrelinquishcontrol;
|
|
IPXGetIntervalMarker(ticks2);
|
|
if (ticks2-ticks)>2
|
|
then begin
|
|
inc(retries);
|
|
{$IFDEF TRACE}
|
|
writeln;
|
|
write('Timeout: resending packet#',SendTransID);
|
|
{$ENDIF}
|
|
IPXsendPacket(SendECB);
|
|
while sendECB.InuseFlag<>0
|
|
do IPXrelinquishControl;
|
|
IPXGetIntervalMarker(ticks);
|
|
end;
|
|
CheckError(retries>50,$0204);
|
|
CheckError(Keypressed,$0205);
|
|
UNTIL AckReceived;
|
|
if SendTransID=1
|
|
then begin
|
|
writeln('Handshake received. Starting file transfer.');
|
|
IPXGetIntervalMarker(TransferStartTicks);
|
|
end;
|
|
{$IFDEF TRACE}
|
|
writeln(' Ackn.#',ListenPepHdr.TransactionID,' received.');
|
|
{$ENDIF}
|
|
FileSize:=FileSize-512;
|
|
|
|
{ fill buffer with next block of data }
|
|
IF FileSize>0
|
|
then begin
|
|
BlockRead(f,SendDataBuffer,512,bytesread);
|
|
CheckError((bytesread<512) and (filesize<>bytesread),$0300);
|
|
end;
|
|
|
|
inc(SendTransID);
|
|
IPXListenForPacket(ListenECB); { start listening for acks again }
|
|
end;
|
|
IPXGetIntervalMarker(TransferEndTicks);
|
|
IPXcancelEvent(ListenECB);
|
|
Writeln('Transfer completed.');
|
|
writeln('Throughput: ', 18*OriginalFileSize/(TransferEndTicks-TransferStartTicks):4:2,' bps');
|
|
IPXcloseSocket(IOsocket);
|
|
close(f);
|
|
|
|
end. |