%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% XL code for the i-protocol
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%-----------------------------------------------------------------------------
%% The data channel
medium ::=
in(chan_in, X)
o (
out(chan_out, recvpak(true, true, X))
# action(drop)
# action(corrupt)
o (
out(chan_out, recvpak(true, false, X))
# out(chan_out, recvpak(false, false, X))
# out(chan_out, recvpak(false, true, X))
)
)
o medium.
%%-----------------------------------------------------------------------------
%% The sender
%%
%% SendState == s(SendSeq, Rack)
%% Packet = packet(PakType, Seq, Ack)
%%
%% Sender's active window = open(Rack, SendSeq).
%% Receiver's active window = upper_closed(RecSeq, Lack).
sender(In) ::=
(
s_sendmsg(In, Mid)
# s_getpkt(In, Mid)
# action(progress) o s_timeout(In, Mid)
)
o sender(Mid).
s_sendmsg(In, Out) ::=
in(user_send)
o s_sendmsg_while1(In, Mid)
o Mid = s(SendSeq, Rack)
o out(med_out, packet(type_DATA, SendSeq, /* RecSeq */ 0))
o eval(NextSend := SendSeq+1)
o Out = s(NextSend, Rack).
s_sendmsg_while1(In, Out) ::=
In = s(SendSeq, Rack)
o if( (eval(SendSeq-Rack > window_size); SendSeq == Rack)
, ( ( s_getpkt(In, Mid)
# action(timeout) o s_timeout(In, Mid)
)
o s_sendmsg_while1(Mid, Out))
, Out = In
).
s_getpkt(In, Out) ::=
in(med_in, RecvPak)
o RecvPak = recvpak(Hck, _Dck, Pak)
o if( Hck == true
, ( Pak = packet(PakType, _Seq, Ack)
o s_handle_ack(Ack, In, Mid)
o if( PakType == type_NAK
, s_handle_nak(Mid, Out, Pak)
, Out = Mid
))
, Out = In
).
s_handle_ack(Ack, In, Out) :-
In = s(SendSeq, Rack),
(in_interval(Ack, open(SendSeq, Rack))
-> Out = s(SendSeq, /* Rack = */ Ack)
; Out = In
).
s_handle_nak(In, In, Pak) ::=
Pak = packet(_PakType, Seq, _Ack)
o In = s(SendSeq, Rack)
o if(in_interval(Seq, open(SendSeq, Rack))
, out(med_out, packet(type_DATA, Seq, /* RecSeq */ 0))
)
.
s_timeout(In, Out) ::=
In = s(SendSeq, Rack)
o (
s_getpkt(In, Out)
#
(
out(med_out, packet(type_NAK, /* PakSeq */ 1, /* RecSeq */ 0))
o if( (not(eval(SendSeq == (Rack+1))))
, ( eval(PakSeq1 := Rack + 1)
o out(med_out, packet(type_DATA,
PakSeq1, /* RecSeq */ 0))
)
)
o Out = In
)
).
%%-----------------------------------------------------------------------------
%% The receiver
%%
%% State == r(SendSeq, RecSeq, Lack, Rack, Nakd, RecBuf)
%% Packet = packet(PakType, Seq, Ack)
%%
%% Receiver's active window = upper_closed(RecSeq, Lack).
receiver(In) ::=
(
r_getpkt(In, Mid)
# action(progress) o r_timeout(In, Mid)
)
o receiver(Mid).
r_getpkt(In, Out) ::=
in(med_in, RecvPak)
o RecvPak = recvpak(Hck, Dck, Pak)
o if( Hck == true
, ( Pak = packet(PakType, _Seq, _Ack)
% o r_handle_ack(Ack, In, Mid)
o if( PakType == type_DATA
, r_handle_data(In, Out, Pak, Dck)
, if( PakType == type_NAK
, r_handle_nak(In, Out, Pak)
, Out = In
)
))
, Out = In
).
r_handle_data(In, Out, Pak, Dck) ::=
In = r(_SendSeq, _RecSeq, Lack, _Rack, _Nakd, _RecBuf)
o Pak = packet(_PakType, Seq, _Ack)
o if( (not(eval(Seq-Lack > window_size)), Seq =\= Lack)
, r_handle_data_correct(In, Out, Pak, Dck)
, Out = In
).
r_handle_data_correct(In, Out, Pak, Dck) ::=
In = r(SendSeq, RecSeq, Lack, Rack, Nakd, RecBuf)
o Pak = packet(_PakType, Seq, _Ack)
o if( Dck == true
, ( remove_from_set(Seq, Nakd, MidNakd)
o Mid = r(SendSeq, RecSeq, Lack, Rack, MidNakd, RecBuf)
o if( eval(Seq == RecSeq + 1)
, r_handle_data_expected_seqno(Mid, Out, Pak)
, r_handle_data_unexpected_seqno(Mid, Out, Pak)
))
% Dck == false
, if( (Seq =\= RecSeq;
(in_set(Seq, RecBuf));
(in_set(Seq, Nakd)))
, ( out(med_out, packet(type_NAK, Seq, RecSeq))
o add_to_set(Seq, Nakd, NewNakd)
o Out = r(SendSeq, RecSeq, RecSeq, Rack, NewNakd, RecBuf)
)
, Out = In
)
).
r_handle_data_expected_seqno(In, Out, Pak) ::=
In = r(SendSeq, RecSeq, Lack, Rack, Nakd, RecBuf)
o Pak = packet(_PakType, _Seq, _Ack)
o eval(MidRecSeq := RecSeq + 1)
o action(user_recv)
o eval(Tmp := MidRecSeq + 1)
o r_supply_to_user(Tmp, MidRecSeq, RecBuf, NewRecSeq, NewRecBuf)
o if( eval((NewRecSeq-Lack) >= window_size//2)
, ( out(med_out, packet(type_ACK, NewRecSeq, NewRecSeq))
o NewLack = NewRecSeq)
, NewLack = Lack
)
o Out = r(SendSeq, NewRecSeq, NewLack, Rack, Nakd, NewRecBuf).
r_supply_to_user(Tmp, RecSeq, RecBuf, NewRecSeq, NewRecBuf) ::=
if( in_set(Tmp, RecBuf)
, ( action(user_recv)
o remove_from_set(Tmp, RecBuf, MidRecBuf)
o eval(Next := Tmp + 1)
o r_supply_to_user(Next, Tmp, MidRecBuf,
NewRecSeq, NewRecBuf))
, (NewRecBuf = RecBuf o NewRecSeq = RecSeq)
).
r_handle_data_unexpected_seqno(In, Out, Pak) ::=
In = r(SendSeq, RecSeq, Lack, Rack, Nakd, RecBuf)
o Pak = packet(_PakType, Seq, _Ack)
o if( (Seq =\= RecSeq,
not(in_set(Seq, RecBuf)))
, ( add_to_set(Seq, RecBuf, NewRecBuf)
o eval(Tmp := RecSeq + 1)
o r_send_naks(Tmp, Seq, RecSeq, Nakd, NewRecBuf, Lack,
NewNakd, NewLack)
o Out = r(SendSeq, RecSeq, NewLack, Rack,
NewNakd, NewRecBuf))
, Out = In
).
r_send_naks(Tmp, Seq, RecSeq, Nakd, RecBuf, Lack, NewNakd, NewLack) ::=
if((Tmp =\= Seq)
, ( if( (not(in_set(Tmp, Nakd)), not(in_set(Tmp, RecBuf)))
, ( out(med_out, packet(type_NAK, Tmp, RecSeq))
o add_to_set(Tmp, Nakd, MidNakd)
o MidLack = RecSeq)
, (MidNakd = Nakd o MidLack = Lack)
)
o eval(Next := Tmp + 1)
o r_send_naks(Next, Seq, RecSeq, MidNakd, RecBuf, MidLack,
NewNakd, NewLack)
)
, (NewNakd = Nakd o NewLack = Lack)
).
r_handle_ack(Ack, In, Out) :-
In = r(SendSeq, RecSeq, Lack, Rack, Nakd, RecBuf),
(in_interval(Ack, open(SendSeq, Rack))
-> Out = r(SendSeq, RecSeq, Lack, /* Rack = */ Ack,
Nakd, RecBuf)
; Out = In
).
r_handle_nak(In, Out, Pak) ::=
if( fixed(fix)
,
Pak = packet(_PakType, _Seq, _Ack)
o In = r(SendSeq, RecSeq, _Lack, Rack, Nakd, RecBuf)
o out(med_out, packet(type_ACK, RecSeq, RecSeq))
o Out = r(SendSeq, RecSeq, RecSeq, Rack, Nakd, RecBuf)
,
Out = In
).
r_timeout(In, Out) ::=
In = r(SendSeq, RecSeq, Lack, Rack, _Nakd, RecBuf)
o Mid = r(SendSeq, RecSeq, Lack, Rack, 0, RecBuf)
o (
r_getpkt(Mid, Out)
#
eval(PakSeq := RecSeq + 1)
o add_to_set(PakSeq, 0, NewNakd)
o out(med_out, packet(type_NAK, PakSeq, RecSeq))
o Out = r(SendSeq, RecSeq, /* Lack = */ RecSeq, Rack,
NewNakd, RecBuf)
).
%%=============================================================================
%% The system
i ::=
( sender(s(1,0))
@ [ user_send/lsend, user_recv/lrecv,
med_in/rl_out, med_out/lr_in
]
| receiver(r(1,0,0,0,0,0))
@ [ user_send/rsend, user_recv/rrecv,
med_in/lr_out, med_out/rl_in
]
| medium
@ [ chan_in/lr_in, chan_out/lr_out]
| medium
@ [ chan_in/rl_in, chan_out/rl_out]
)
\ {lr_in, lr_out, rl_in, rl_out}.
%%-----------------------------------------------------------------------------
%% system configuration
config(WS,Fix) :-
abolish_all_tables,
retractall(window_size(_)),
retractall(seq(_)),
retractall(fixed(_)),
S is 2*WS,
assert(window_size(WS)),
assert(seq(S)),
assert(fixed(Fix)).
%%=============================================================================
%% The livelock property
try += tx6 \/ diam(-nil, try).
tx6 -= diam([timeout,nop,tau], tx6).
%%=============================================================================
%% Some arithmetic
:- import ground/1 from basics.
eval(X = Y) :- !, X = Y.
eval(X == Y) :- !, eval(X, U), eval(Y, V), modulus(U, Ua), modulus(V, Va), Ua == Va.
eval(X := Y) :- !, eval(Y, U), modulus(U, X).
eval(X is Y) :- !, eval(Y, U), modulus(U, X).
eval(X > Y) :- !, eval(X, U), eval(Y, V), modulus(U, Ua), modulus(V, Va), Ua > Va.
eval(X < Y) :- !, eval(X, U), eval(Y, V), modulus(U, Ua), modulus(V, Va), Ua < Va.
eval(X >= Y) :- !, eval(X, U), eval(Y, V), modulus(U, Ua), modulus(V, Va), Ua >= Va.
eval(X =< Y) :- !, eval(X, U), eval(Y, V), modulus(U, Ua), modulus(V, Va), Ua =< Va.
eval(not(E)) :- !, not(eval(E)).
eval(A+B, V) :- !, eval(A, Va), eval(B, Vb), V is Va+Vb.
eval(A-B, V) :- !, eval(A, Va), eval(B, Vb), V is Va-Vb.
eval(A*B, V) :- !, eval(A, Va), eval(B, Vb), V is Va*Vb.
eval(A/B, V) :- !, eval(A, Va), eval(B, Vb), V is Va/Vb.
eval(A//B, V) :- !, eval(A, Va), eval(B, Vb), V is Va//Vb.
eval(window_size, V) :- !, window_size(V).
eval(E, V) :- V is E.
modulus(E, V) :- seq(Seq), X is E mod Seq, abs(X, V).
abs(X, V) :- ( X < 0 -> (seq(Seq), V is X+Seq) ; V = X).
%% Now, some interval stuff
in_interval(X, open(L,U)) :-
X =\= L,
eval((L-X) =< window_size),
eval((X-U) =< window_size).
in_open_interval(X, L,U) :-
X =\= L,
eval((L-X) =< window_size),
eval((X-U) =< window_size).
in_interval(X, upper_closed(L, U)) :-
(L > U -> (X > L; X =< U)
; (X > L, X =< U)).
in_interval(X, closed(L, U)) :-
(L > U -> (X >= L; X =< U)
; (X >= L, X =< U)).
%% Finally, some set stuff
in_set(Element, Set) :-
1 is ((Set >> Element) mod 2).
add_to_set(Element, Set, NewSet) :-
in_set(Element, Set)
-> NewSet = Set
; NewSet is Set + (1 << Element).
remove_from_set(Element, Set, NewSet) :-
in_set(Element, Set)
-> NewSet is Set - (1 << Element)
; NewSet = Set.