/*
* PROMELA Validation Model
* 协议层验证
*
* 验证BCL可靠性协议A version5.0
*
* Yuhuang
* 2007-7-26
*/
/*
* 本版本特点:采用集合点来通信,允许ACK、DATA丢包,实现了队列自动重发。
* 加入了对传输介质的模拟。介质可以丢包,导致包失序。
*
* 未完全模拟的问题:ACK、DATA失序问题
*/
/* ************* 数据结构定义 ************ */
/* 序号范围定义 */
# define WIN 9
/* 发送队列大小定义 */
# define QSIZE 4
/* 消息类型定义 */
mtype = { ACK , DATA }
/*
* { ACK, s_seqno }
*/
chan sevts = [ 0 ] of { mtype , byte };
chan revts = [ 0 ] of { mtype , byte };
/*
* { DATA, r_seqno}
* 数据队列
*/
chan sdata = [ 0 ] of { mtype , byte };
chan rdata = [ 0 ] of { mtype , byte };
/* 发送记录队列 */
/* 当ACK发生的时候,ACK(含)之前的内容都被清除 */
byte head_seq;
byte tail_seq;
byte cur_seq;
/*
#define inc(x) (x=(x+1)%WIN)
*/
proctype sender2media()
{
byte seq;
do
:: sdata ? DATA , seq ->
if
:: rdata ! DATA , seq
:: skip
fi
od
}
proctype receiver2media()
{
byte seq;
do
:: revts ? ACK , seq ->
if
:: sevts ! ACK , seq
:: skip
fi
od
}
proctype sender(byte id)
{
byte s;
head_seq = 0 ;
tail_seq = 0 ;
cur_seq = 0 ;
do
:: (tail_seq + WIN - head_seq + 1 ) % WIN != QSIZE -> /* 队列不为满,允许发送 */
if
:: sdata ! DATA , cur_seq /* normal send action */
fi;
progress_2 : cur_seq = (cur_seq + 1 ) % WIN;
tail_seq = (tail_seq + 1 ) % WIN;; /* 更新tail, head保持不变 */
:: sevts ? ACK , s ->
/* 进行ACK失序处理 */
/* 若s不在当前的head_seq~tail_seq范围内,则简单忽略之 */
if
:: (head_seq < tail_seq) -> /* 顺序递增情景 */
if
:: (s > tail_seq || s < head_seq ) ->
goto endofack
:: else
fi
:: (head_seq > tail_seq) -> /* 非递增情景 */
if
:: ( s < head_seq && s > tail_seq ) ->
goto endofack
:: else
fi
:: else
fi;
assert (s < WIN);
head_seq = (s + 1 ) % WIN; /* 根据ACK更新head_seq,暗含了累积更新 */
cur_seq = head_seq;
endofack : skip
:: ((cur_seq != tail_seq) && (tail_seq - head_seq) != 0 ) ->
/* 队列不为空,允许发送. 此情景配合timeout时重发使用 */
/* 第一个判断是为了防止发送不存在内容 */
if
:: sdata ! DATA , cur_seq /* normal send action */
fi;
cur_seq = (cur_seq + 1 ) % WIN;
:: timeout -> /* 超时 */
/* 更新指针,准备重发队列 */
cur_seq = head_seq;
/* 尝试重发队列 */
if
:: sdata ! DATA , cur_seq /* normal send action */
fi;
cur_seq = (cur_seq + 1 ) % WIN; /* 发送了一个包,更新cur_seq */
/* 这里不用更新tail_seq, 因为这个值只在有新的包加入到队列的时候才更新 */
od
}
proctype receiver(byte id)
{
byte expected_seqno;
byte s;
expected_seqno = 0 ;
do
:: rdata ? DATA , s ->
if
:: (s != expected_seqno) -> /* 非期望数据包 */
if
:: revts ! ACK , (expected_seqno + WIN - 1 ) % WIN /* some acks was lost, ack again! */
fi
:: (s == expected_seqno) -> /* 期望数据包 */
if
:: revts ! ACK , expected_seqno -> /* ack */
expected_seqno = (expected_seqno + 1 ) % WIN
fi
fi
od
}
init
{
atomic{
run sender( 0 );
run sender2media();
run receiver( 1 );
run receiver2media();
}
}
* PROMELA Validation Model
* 协议层验证
*
* 验证BCL可靠性协议A version5.0
*
* Yuhuang
* 2007-7-26
*/
/*
* 本版本特点:采用集合点来通信,允许ACK、DATA丢包,实现了队列自动重发。
* 加入了对传输介质的模拟。介质可以丢包,导致包失序。
*
* 未完全模拟的问题:ACK、DATA失序问题
*/
/* ************* 数据结构定义 ************ */
/* 序号范围定义 */
# define WIN 9
/* 发送队列大小定义 */
# define QSIZE 4
/* 消息类型定义 */
mtype = { ACK , DATA }
/*
* { ACK, s_seqno }
*/
chan sevts = [ 0 ] of { mtype , byte };
chan revts = [ 0 ] of { mtype , byte };
/*
* { DATA, r_seqno}
* 数据队列
*/
chan sdata = [ 0 ] of { mtype , byte };
chan rdata = [ 0 ] of { mtype , byte };
/* 发送记录队列 */
/* 当ACK发生的时候,ACK(含)之前的内容都被清除 */
byte head_seq;
byte tail_seq;
byte cur_seq;
/*
#define inc(x) (x=(x+1)%WIN)
*/
proctype sender2media()
{
byte seq;
do
:: sdata ? DATA , seq ->
if
:: rdata ! DATA , seq
:: skip
fi
od
}
proctype receiver2media()
{
byte seq;
do
:: revts ? ACK , seq ->
if
:: sevts ! ACK , seq
:: skip
fi
od
}
proctype sender(byte id)
{
byte s;
head_seq = 0 ;
tail_seq = 0 ;
cur_seq = 0 ;
do
:: (tail_seq + WIN - head_seq + 1 ) % WIN != QSIZE -> /* 队列不为满,允许发送 */
if
:: sdata ! DATA , cur_seq /* normal send action */
fi;
progress_2 : cur_seq = (cur_seq + 1 ) % WIN;
tail_seq = (tail_seq + 1 ) % WIN;; /* 更新tail, head保持不变 */
:: sevts ? ACK , s ->
/* 进行ACK失序处理 */
/* 若s不在当前的head_seq~tail_seq范围内,则简单忽略之 */
if
:: (head_seq < tail_seq) -> /* 顺序递增情景 */
if
:: (s > tail_seq || s < head_seq ) ->
goto endofack
:: else
fi
:: (head_seq > tail_seq) -> /* 非递增情景 */
if
:: ( s < head_seq && s > tail_seq ) ->
goto endofack
:: else
fi
:: else
fi;
assert (s < WIN);
head_seq = (s + 1 ) % WIN; /* 根据ACK更新head_seq,暗含了累积更新 */
cur_seq = head_seq;
endofack : skip
:: ((cur_seq != tail_seq) && (tail_seq - head_seq) != 0 ) ->
/* 队列不为空,允许发送. 此情景配合timeout时重发使用 */
/* 第一个判断是为了防止发送不存在内容 */
if
:: sdata ! DATA , cur_seq /* normal send action */
fi;
cur_seq = (cur_seq + 1 ) % WIN;
:: timeout -> /* 超时 */
/* 更新指针,准备重发队列 */
cur_seq = head_seq;
/* 尝试重发队列 */
if
:: sdata ! DATA , cur_seq /* normal send action */
fi;
cur_seq = (cur_seq + 1 ) % WIN; /* 发送了一个包,更新cur_seq */
/* 这里不用更新tail_seq, 因为这个值只在有新的包加入到队列的时候才更新 */
od
}
proctype receiver(byte id)
{
byte expected_seqno;
byte s;
expected_seqno = 0 ;
do
:: rdata ? DATA , s ->
if
:: (s != expected_seqno) -> /* 非期望数据包 */
if
:: revts ! ACK , (expected_seqno + WIN - 1 ) % WIN /* some acks was lost, ack again! */
fi
:: (s == expected_seqno) -> /* 期望数据包 */
if
:: revts ! ACK , expected_seqno -> /* ack */
expected_seqno = (expected_seqno + 1 ) % WIN
fi
fi
od
}
init
{
atomic{
run sender( 0 );
run sender2media();
run receiver( 1 );
run receiver2media();
}
}