dhcp

#include <iostream>
#include <cstring>
#include <string>
#include <algorithm>

using namespace std;

const int N = 1e4 + 10;
//四个正整数和一个字符串,分别是:、、、 和 ,
int n, m, t_def, t_max, t_min;
string h;
struct IP
{
	int state; //0:未分配, 1:待分配, 2:占用, 3过期
	int t;	//过期时间
	string owner;	//占用者
}ip[N];
void update_ip(int t) {
	/*处于待分配和占用状态的 IP 地址拥有一个大于零的过期时刻。
	在到达该过期时刻时,
	若该地址的状态是待分配,则该地址的状态会自动变为未分配,且占用者清空,过期时刻清零;
	否则该地址的状态会由占用自动变为过期,且过期时刻清零。
	处于未分配和过期状态的 IP 地址过期时刻为零,即没有过期时刻。*/
	for (size_t i = 1; i <= n; i++){
		if (ip[i].state == 1 && ip[i].t && ip[i].t <= t) {
			ip[i].state = 0;
			ip[i].owner = "";
			ip[i].t = 0;
		}
		else if (ip[i].state == 2 && ip[i].t  && ip[i].t <= t) {
			ip[i].state = 3;
			ip[i].t = 0;
		}
		else if (ip[i].state == 0 || ip[i].state == 3) {	//细节
			ip[i].t = 0;
		}
	}
}
int get_ip_by_owner(string owner) {
	for (size_t i = 1; i <= n; i++)
	{
		if (ip[i].owner == owner)
		{
			return i;
		}
	}

	return 0;
}

int get_ip_by_state(int state) {
	for (size_t i = 1; i <= n; i++)
	{
		if (ip[i].state == state) {
			return i;
		}
	}
	return 0;
}
int main() {
	cin >> n >> t_def >> t_max >> t_min >> h;
	cin >> m;
	while (m--){
		//第  个报文是在  时刻收到
		int t;
		string client, server, type;
		int id, te;//过期时刻
		cin >> t >> client >> server >> type >> id >> te;
		//否为本机,为 *,若不是,则判断类型是否为 Request,若不是,则不处理;
		if (server != h && server != "*") {
			if(type != "REQ")
				continue;
		}
		//若类型不是 Discover、Request 之一,则不处理;
		if (type != "DIS"&&type != "REQ")	continue;
		//若接收主机为 *,但类型不是 Discover,或接收主机是本机,但类型是 Discover,则不处理。
		if (server == "*"&&type != "DIS")	continue;
		if (server == h && type == "DIS")	continue;
		update_ip(t);
		//对于 Discover 报文,按照下述方法处理:
		if (type == "DIS") {
			/*检查是否有占用者为发送主机的 IP 地址:
				若有,则选取该 IP 地址;
				若没有,则选取最小的状态为未分配的 IP 地址;
				若没有,则选取最小的状态为过期的 IP 地址;
				若没有,则不处理该报文,处理结束;*/
			int k = get_ip_by_owner(client);
			if (!k) k = get_ip_by_state(0);
			if (!k) k = get_ip_by_state(3);
			if (!k) continue;
			//将该 IP 地址状态设置为待分配,占用者设置为发送主机;
			ip[k].state = 1;
			ip[k].owner = client;
			/*
			若报文中过期时刻为 0 ,则设置过期时刻为 t + t_def ;t
			否则根据报文中的过期时刻和收到报文的时刻计算过期时间,
			判断是否超过上下限:
				若没有超过,则设置过期时刻为报文中的过期时刻;
				否则则根据超限情况设置为允许的最早或最晚的过期时刻;*/
			if (te == 0) {
				te = t + t_def;
			}
			else {
				if (te > t + t_max)	te = t + t_max;
				else if (te < t + t_min)	te = t + t_min;
			}
			ip[k].t = te;//记得加过期时间
			//向发送主机发送 Offer 报文,其中,IP 地址为选定的 IP 地址,过期时刻为所设定的过期时刻。
			printf("%s %s OFR %d %d\n", h.c_str(), client.c_str(), k, te);
		}
		//对于 Request 报文,按照下述方法处理
		if (type == "REQ") {
			/*
			检查接收主机是否为本机:
				若不是,则找到占用者为发送主机的所有 IP 地址,
					对于其中状态为待分配的,将其状态设置为未分配,并清空其占用者,清零其过期时刻,处理结束;
					*/
			if (server != h) {
				for (size_t i = 1; i <= n; i++){
					if (ip[i].owner == client) {
						if (ip[i].state == 1) {
							ip[i].state = 0;
							ip[i].owner = "";
							ip[i].t = 0;
						}
					}
				}
				continue;
			}
			/*
			检查报文中的 IP 地址是否在地址池内,且其占用者为发送主机,
			若不是,则向发送主机发送 Nak 报文,处理结束;*/
			if (id > n || id < 0 || ip[id].owner != client) {
				//dhcp b NAK 2 0
				printf("%s %s NAK %d 0\n", h.c_str(), client.c_str(), id);
				continue;
			}
			/*
			无论该 IP 地址的状态为何,将该 IP 地址的状态设置为占用;
			与 Discover 报文相同的方法,设置 IP 地址的过期时刻;
			向发送主机发送 Ack 报文。*/
			ip[id].state = 2;
			if (te == 0) { //注意超时定义
				te = t + t_def;
			}
			else {
				if (te > t + t_max)	te = t + t_max;
				else if (te < t + t_min)	te = t + t_min;
			}
			ip[id].t = te;
			//dhcp c ACK 3 20
			printf("%s %s ACK %d %d\n", h.c_str(), client.c_str(), id, te);

		}

	}
	return 0;

}
上一篇:属性问题展开的selinux权限介绍


下一篇:Tennessee Eastman(TE)田纳西-伊斯曼仿真平台应用试验与分析