烤全羊啊嗯

#include <stdio.h>
#include <string.h>

#include "protocol.h"
#include "datalink.h"

#define MAX_SEQ				15
#define CACHE_SIZE			((MAX_SEQ+1)/2)
#define ACK_TIMEOUT_LMT		240
#define DATA_TIMEOUT_LMT	2800

#define INCREASE(X) do {	\
	if(X < MAX_SEQ) {		\
		X++;				\
	} else {				\
		X = 0;				\
	}						\
} while(0)					\

typedef enum {
	false,
	true
} bool;

typedef unsigned char byte;

typedef struct {
	byte			kind; /* FRAME_DATA, FRAME_ACK, FRAME_NAK */
	byte			ack;
	byte			seq;
	byte			data[PKT_LEN];
	unsigned int	crc32;
} FRAME;

static bool phyLayerReady		= false;	// 物理層狀態
static bool noNAK				= true;		// 發NAK了嗎

static void putFrame(byte* frame, int len) {
	*(unsigned int*)(frame + len) = crc32(frame, len);
	send_frame(frame, len + 4);
	phyLayerReady = false;
}

static int between(byte a, byte b, byte c) {
	return  ((a <= b) && (b < c)) ||
			((c < a) && (a <= b)) ||
			((b < c) && (c < a));
}

static void sendFrame(
	byte kind,
	byte seq,
	byte expFrame,
	byte buffer[][PKT_LEN]
) {
	// 數據幀長度爲PKT_LEN + 3 + 4
	// ACK & NAK所需要的幀的長度爲2
	FRAME frame;
	frame.kind = kind;
	frame.ack = (expFrame + MAX_SEQ) % (MAX_SEQ + 1);

	if (kind == FRAME_DATA) {
		frame.seq = seq;
		memcpy(frame.data, buffer[seq % CACHE_SIZE], PKT_LEN);
		putFrame((byte*)&frame, 3 + PKT_LEN);
		start_timer(seq % CACHE_SIZE, DATA_TIMEOUT_LMT);
	}
	else if (kind == FRAME_NAK) {
		noNAK = false;
		putFrame((byte*)&frame, 2);
	}
	else if (kind == FRAME_ACK) {
		putFrame((byte*)&frame, 2);
	}

	stop_ack_timer();
}

int main(int argc, char* argv[]) {

	static byte expACK = 0,				// 發送窗口下界
		nextFrame2Send = 0;				// 發送窗口上界
	static byte expFrame = 0,			// 接收窗口下界
		tooFar = CACHE_SIZE;			// 接收窗口上界+1
	static byte nbuffered = 0;			// 記錄bufferIndex
	static byte
		oBuf[CACHE_SIZE][PKT_LEN],		// 輸出暫存區
		iBuf[CACHE_SIZE][PKT_LEN];		// 輸入暫存區

	bool arrived[CACHE_SIZE] = { false };

	FRAME	frame;
	size_t	length = 0;
	int		event,
			arg;

	protocol_init(argc, argv);
	enable_network_layer();

	while (1) {
		event = wait_for_event(&arg);

		switch (event) {
		case NETWORK_LAYER_READY:
			nbuffered++;
			get_packet(oBuf[nextFrame2Send % CACHE_SIZE]);
			sendFrame(FRAME_DATA, nextFrame2Send, expFrame, oBuf);

			INCREASE(nextFrame2Send);
			break;

		case PHYSICAL_LAYER_READY:
			phyLayerReady = true;
			break;

		case FRAME_RECEIVED:
			length = recv_frame((byte*)&frame, sizeof frame);

			// 如果爲正常數據幀,檢測seqNum判斷是否應該接收
			if (length < 5 || crc32((byte*)&frame, length) != 0) {
				if (noNAK)
					sendFrame(FRAME_NAK, 0, expFrame, oBuf);
				dbg_event("--------Bad CRC Checksum--------\n");
				break;
			}

			if (frame.kind == FRAME_ACK) {
				dbg_frame("Recv ACK  %d\n", frame.ack);
			}
			else if (frame.kind == FRAME_DATA) {
				if ((frame.seq != expFrame) && noNAK) {
					sendFrame(FRAME_NAK, 0, expFrame, oBuf);
				}
				else {
					// 是需要的幀
					// 啓動ACK定時器,確定發送獨立幀的ACK
					start_ack_timer(ACK_TIMEOUT_LMT);
				}

				// 如果窗口內的幀未到達過,移動接收窗口
				if  (between(expFrame, frame.seq, tooFar) &&
					(arrived[frame.seq % CACHE_SIZE] == 0)
				) {
					dbg_frame("Recv DATA %d %d, ID %d\n", frame.seq, frame.ack, *(short*)frame.data);
					
					arrived[frame.seq % CACHE_SIZE] = 1;
					memcpy(iBuf[frame.seq % CACHE_SIZE], frame.data, length - 7);
					
					// 一次性移動接收窗口 & 上傳一個幀到應用層
					while (arrived[expFrame % CACHE_SIZE]) {
						put_packet(
							iBuf[expFrame % CACHE_SIZE], length - 7);

						// 清理狀態變量
						noNAK = true;
						arrived[expFrame % CACHE_SIZE] = 0;

						// 移動窗口
						INCREASE(expFrame);
						INCREASE(tooFar);

						// 檢查獨立幀的ACK是否被需要
						start_ack_timer(ACK_TIMEOUT_LMT);
					}
				}
			}
			else if ((frame.kind == FRAME_NAK) && between(expACK, (frame.ack + 1) % (MAX_SEQ + 1), nextFrame2Send)) {
				dbg_frame("Recv NAK %d\n", frame.ack);
				// 選擇重傳
				sendFrame(
					FRAME_DATA,
					(frame.ack + 1) % (MAX_SEQ + 1),
					expFrame,
					oBuf
				);
			}
			while (between(expACK, frame.ack, nextFrame2Send)) {
				nbuffered--;
				stop_timer(expACK % CACHE_SIZE);
				INCREASE(expACK);
			}
			break;

		case DATA_TIMEOUT:
			dbg_event("--------DATA %d timeout--------\n", arg);
			// 超時重傳
			sendFrame(FRAME_DATA, expACK, expFrame, oBuf);
			break;

		case ACK_TIMEOUT:
			dbg_event("--------ACK %d timeout--------\n", arg);
			// ACK超時,嘗試確認
			sendFrame(FRAME_ACK, 0, expFrame, oBuf);
		}

		if (nbuffered < CACHE_SIZE && phyLayerReady) {
			enable_network_layer();
		}
		else {
			disable_network_layer();
		}
	}
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章