include order
module tcp_channel(addr,pkt) = {
object sndr = {
action send(p : pkt)
}
object rcvr = {
action recv(p:pkt)
}
instance index : unbounded_sequence
object spec = {
individual send_idx : index.t
individual recv_idx : index.t
relation sent(I:index.t,P:pkt)
after init {
send_idx := 0;
recv_idx := 0;
sent(I,P) := false;
}
before sndr.send(p : pkt) {
sent(send_idx,p) := true;
send_idx := index.next(send_idx);
}
before rcvr.recv(p : pkt) {
assert recv_idx < send_idx;
assert sent(recv_idx,p);
sent(recv_idx,p) := false;
recv_idx := index.next(recv_idx);
}
}
object impl = {
action internal(p:pkt) = {
call rcvr.recv(p);
}
implement sndr.send(p : pkt) {
seriously need to do something here!
}
}
trusted isolate iso = impl with spec
}
include tcp_impl
module tcp_network(addr,pkt) = {
type socket
calls
action close(self:addr,s:socket)
action connect(self:addr,other:addr) returns (s:socket)
action send(self:addr,s:socket,p:pkt) returns (ok:bool)
callbacks
action accept(self:addr,s:socket,other:addr)
action recv(self:addr,s:socket,p:pkt)
action failed(self:addr,s:socket)
action connected(self:addr,s:socket)
var open(A:addr,S:socket) : bool
var req(A1:addr,S1:socket,A2:addr) : bool
var ack(A1:addr,S1:socket) : bool
var conn(A1:addr,S1:socket,A2:addr,S2:socket) : bool
var sent_to(A:addr,S:socket,P:pkt) : bool
object spec = {
after init {
open(A,S) := false;
req(A,S,A1) := false;
ack(A,S) := false;
conn(A1,S1,A2,S2) := false;
sent_to(A,S,P) := false;
}
after connect {
assume ~open(self,s) & ~req(self,s,A) & ~ack(self,s); # can't return socket in use
req(self,s,other) := true;
}
around accept {
require exists S. req(other,S,self);
require ~open(self,s) & ~req(self,s,A) & ~ack(self,s); # can't return socket in use
...
open(self,s) := true;
if some (s2 : socket) req(other,s2,self) {
conn(self,s,other,s2) := true;
conn(other,s2,self,s) := true;
req(other,s2,self) := false;
ack(other,s2) := true
}
}
around connected {
require ack(self,s);
...
open(self,s) := true;
ack(self,s) := false;
}
around send {
require open(self,s);
...
if ok {
if some (other:addr,s2:socket) conn(self,s,other,s2) {
sent_to(other,s2,p) := true
}
}
}
before recv {
require open(self,s);
require sent_to(self,s,p);
}
around close {
require open(self,s);
...
open(self,s) := false;
sent_to(self,s,P) := false;
conn(A,S,self,s) := false;
conn(self,s,A,S) := false;
}
around failed {
require exists A. req(self,s,A) | ack(self,s) | open(self,s);
...
open(self,s) := false;
req(self,s,A) := false;
ack(self,s) := false;
sent_to(self,s,P) := false;
conn(A,S,self,s) := false;
}
invariant ~(open(A,S) & (req(A,S,A1) | ack(A,S))) & ~(req(A,S,A1) & ack(A,S))
invariant req(A,S,A1) & req(A,S,A2) -> A1 = A2
invariant (conn(A,S,A1,S1) | sent_to(A1,S1,P)) -> (open(A1,S1) | ack(A1,S1))
invariant conn(A1,S1,A,S) -> (open(A1,S1) | ack(A1,S1))
}
implementation {
instance impl(X:addr) : tcp_impl(addr,pkt,X,5990)
}
isolate iso = this
attribute test = impl
}
module simple_tcp(addr,pkt) = {
action recv(dst:addr,v:pkt)
action send(src:addr,dst:addr,v:pkt)
specification {
relation sent(V:pkt, N:addr)
after init {
sent(V, N) := false
}
before send {
sent(v,dst) := true
}
before recv {
assert sent(v,dst)
}
}
implementation {
instance tcp : tcp_network(addr,pkt)
object proc(self:addr) = {
relation isup(A:addr)
function sock(A:addr) : tcp.socket
relation pend(A:addr)
after init {
isup(A) := false;
pend(A) := false;
var foo := self;
call tcp.listen(foo);
}
implement send(dst:addr,v:pkt) {
if ~isup(dst) {
if ~pend(dst) {
sock(dst) := tcp.connect(self,dst);
pend(dst) := true
}
} else {
var ok := tcp.send(self,sock(dst),v);
if ~ok {
call tcp.close(self,sock(dst));
sock(dst) := tcp.connect(self,dst);
isup(dst) := false;
pend(dst) := true
}
}
}
implement tcp.recv(s:tcp.socket,v:pkt) {
call recv(self,v)
}
implement tcp.connected(s:tcp.socket) {
if some(other:addr) pend(other) & sock(other) = s {
pend(other) := false;
isup(other) := true;
}
}
implement tcp.accept(s:tcp.socket,other:addr) {
we ignore accept events
}
implement tcp.failed(s:tcp.socket) {
if some(other:addr) (isup(other) | pend(other)) & sock(other) = s {
isup(other) := false;
pend(other) := true;
sock(other) := tcp.connect(self,other);
isup(other) := false;
pend(other) := false;
}
}
specification {
invariant isup(A) -> tcp.open(self,sock(A))
invariant pend(A) -> (isup(A) | tcp.req(self,sock(A),A) | tcp.ack(self,sock(A)))
invariant tcp.conn(self,S,A1,S1) -> S = sock(A1) & (isup(A1) | tcp.ack(self,S) & pend(A1))
invariant (isup(A) | pend(A)) & tcp.conn(self,sock(A),A1,S1) -> A = A1
invariant (isup(A) | pend(A)) & (isup(A1) | pend(A1)) & sock(A) = sock(A1) -> A = A1
invariant tcp.sent_to(A,S,V) -> sent(V,A)
}
}
}
isolate iso = this
attribute test = impl
}