gnugk5.5源码分析(4)之ras相关消息处理实现

一、ras消息类型

在h225.h中,H225_RasMessage有定义了H323协议上的各类ras消息。

    enum Choices {
      e_gatekeeperRequest,
      e_gatekeeperConfirm,
      e_gatekeeperReject,
      e_registrationRequest,
      e_registrationConfirm,
      e_registrationReject,
      e_unregistrationRequest,
      e_unregistrationConfirm,
      e_unregistrationReject,
      e_admissionRequest,
      e_admissionConfirm,
      e_admissionReject,
      e_bandwidthRequest,
      e_bandwidthConfirm,
      e_bandwidthReject,
      e_disengageRequest,
      e_disengageConfirm,
      e_disengageReject,
      e_locationRequest,
      e_locationConfirm,
      e_locationReject,
      e_infoRequest,
      e_infoRequestResponse,
      e_nonStandardMessage,
      e_unknownMessageResponse,
      e_requestInProgress,
      e_resourcesAvailableIndicate,
      e_resourcesAvailableConfirm,
      e_infoRequestAck,
      e_infoRequestNak,
      e_serviceControlIndication,
      e_serviceControlResponse,
      e_admissionConfirmSequence
    };

而与之相对应的,就是表述各ras的类定义,各类分别代表着当前这种消息类型所数据字段。

class H225_GatekeeperRequest;
class H225_GatekeeperConfirm;
class H225_GatekeeperReject;
class H225_RegistrationRequest;
class H225_RegistrationConfirm;
class H225_RegistrationReject;
class H225_UnregistrationRequest;
class H225_UnregistrationConfirm;
class H225_UnregistrationReject;
class H225_AdmissionRequest;
class H225_AdmissionConfirm;
class H225_AdmissionReject;
class H225_BandwidthRequest;
class H225_BandwidthConfirm;
class H225_BandwidthReject;
class H225_DisengageRequest;
class H225_DisengageConfirm;
class H225_DisengageReject;
class H225_LocationRequest;
class H225_LocationConfirm;
class H225_LocationReject;
class H225_InfoRequest;
class H225_InfoRequestResponse;
class H225_NonStandardMessage;
class H225_UnknownMessageResponse;
class H225_RequestInProgress;
class H225_ResourcesAvailableIndicate;
class H225_ResourcesAvailableConfirm;
class H225_InfoRequestAck;
class H225_InfoRequestNak;
class H225_ServiceControlIndication;
class H225_ServiceControlResponse;
class H225_ArrayOf_AdmissionConfirm;

二、gnugk对接各类ras消息

gnugk对各ras消息的对接,主要是运用到了模板工厂方法和GatekeeperMessage类。其关系类图可以如下。
在这里插入图片描述

从关系图中可以看出,RasMsg作为所有ras消息的基类,继承自Task类,以便于各个消息能多线程异步处理,互不影响,因此RasMsg需要实现Task协定的Exec接口;

void RasMsg::Exec()
{
	PTRACE(1, "RAS\t" << m_msg->GetTagName() << " Received from " << AsString(m_msg->m_peerAddr, m_msg->m_peerPort));
	if (Process()) {
		Reply(m_authenticators);
	}
}

从RasMsg::Exec的实现来看,逻辑很简单,调用Process方法作具体的处理,然后调用Reply发送响应,因此RasMsg重新约定了纯虚接口virtual bool Process() = 0,这个接口需要针对各个不同的RAS消息单独实现;除此之外,RasMsg还约定了另外两个纯虚接口virtual int GetSeqNum() const = 0和virtual H225_NonStandardParameter *GetNonStandardParam() = 0,但是gnugk对于各Ras消息需要实现Process接口这一行为,并不是采用各个消息类型都继承RasMsg,然后定义相应类型的类,而是结合了模板工厂Factory的Creator1,定义RasPDU模板类来实现;因此对于每个具体的ras只需要重载实现Process即可,不需要每个都重新定义类,如template<> bool RasPDU<H225_GatekeeperRequest>::Process()表示对GRQ的Process处理实现;其中针对RRQ、ARQ比较特殊些,采用了继承RasPDU的方式来实现;

另外,也还需要结合GatekeeperMessage类和RasListener类来实现数据的读取和发送。

2.1 GatekeeperMessage类

众所周知,通信交互就存在数据的读取和发送,而对ras的消息读取和发送,以及数据的保存就主要由GatekeeperMessage类来完成。从代码定义就可以看到,最主要的成员方法是bool Read(RasListener *)读取和bool Reply(GkH235Authenticators * authenticators)发送;而数据成员就很自然的是H225_RasMessage m_recvRAS和H225_RasMessage m_replyRAS;也就是说,数据从各RasListener读取上来后,就保存在m_recvRAS中,而在完成了gnugk内部对不同数据的逻辑处理后,最生成的响应结果,就保存在m_replyRAS,然后通话发送方法发回到请求方。
换句说,一个GatekeeperMessage类实例,就代表着一个ras的完整的生命周期。

class GatekeeperMessage {
public:
	GatekeeperMessage() : m_peerPort(0), m_socket(NULL)
#ifdef HAS_H46017
		, m_h46017Socket(NULL)
#endif
		{ }
	unsigned GetTag() const { return m_recvRAS.GetTag(); }
	const char *GetTagName() const;
	bool Read(RasListener *);
#ifdef HAS_H46017
	bool Read(const PBYTEArray & buffer);
#endif
	bool Reply(GkH235Authenticators * authenticators);

	PPER_Stream m_rasPDU;
	H225_RasMessage m_recvRAS;
	H225_RasMessage m_replyRAS;
	PIPSocket::Address m_peerAddr;
	WORD m_peerPort;
	PIPSocket::Address m_localAddr;
	RasListener * m_socket;
#ifdef HAS_H46017
	CallSignalSocket * m_h46017Socket;
#endif
};

2.2 各ras消息对接到模板工厂模型

template<class RAS>
class RasPDU : public RasMsg {
public:
	typedef RAS RasClass;

	RasPDU(GatekeeperMessage *m) : RasMsg(m), request(m->m_recvRAS) { }
	virtual ~RasPDU() { }

	// override from class RasMsg
	virtual bool Process() { return false; }
	
	typedef Factory<RasMsg, unsigned>::Creator1<GatekeeperMessage *> RasCreator;
	struct Creator : public RasCreator {
		Creator() : RasCreator(RasInfo<RAS>::tag) { }
		virtual RasMsg *operator()(GatekeeperMessage *m) const { return new RasPDU<RAS>(m); }
	};
};

上面这个只是截取了RasPDU继承自RasMsg,并对接模板工厂的实现部分,并不是RasPDU全部定义。
如前面所述,各个类型的RAS消息,通过RasPDU这个模板类来实现自己的Process处理流程。RasPDU,接受的模板参数类型RAS,实际上指的就是H225_GatekeeperRequest这类H225的消息类;我们知道RasPDU只是一个模板类,只有在具体实例化时,才能具体确定;而为了在其它地方都能成功各类型的RAS消息,在RasPDU内部定义了Creator,该Creator继承自Factory的Creator1;并且指定了返回的产品实例类型是RasMsg,产品的标识类型是unsigned,而且接受一个参数,参数类型是GatekeeperMessage *;从对Factory的Creator1的定义,可知其子类需要重载实现约定的实例运算符operator(),从代码定义中,也看到了Creator确实重载实现了这个操作符。

2.3 理解RasInfo的实现

在Creator的构造函数中,其向上构造父类时,传递的产品标识是unsigned的,而且其值为RasInfo::tag,那么这个值具体等于多少,为什么对于具体的RAS类,RasInfo::tag能唯一表示标识它呢?这个也是需要梳理清楚的。
对于RasInfo::tag,我们先不管其成员变量tag的值,先来看下RasInfo的定义,从调用方式也可以看出,这也是一个模板类。要理解RasInfo的定义实现,就需要查看rasinfo.h。

首先,定义一个RasTag类,表示RAS tag值;其逻辑也简单,就是在特化后,进行操作转为unsigned时,返回特化时的值 I;也就是实现操作符unsigned()。

template<int I> struct RasTag {
	operator unsigned() const { return I; }
};

其次,定义一个RasType类,映射每个具体的Ras tag与相应对应的Ras类的类型。

template<int> struct RasType;

如GAQ/GCF/GRJ三种消息各自的tag值和类类型的关联如下,比如tag值为H225_RasMessage::e_gatekeeperRequest时,其对应的类类型为H225_GatekeeperRequest ,并且重命名为Type;

template<> struct RasType<H225_RasMessage::e_gatekeeperRequest> {
	typedef H225_GatekeeperRequest Type;
};
template<> struct RasType<H225_RasMessage::e_gatekeeperConfirm> {
	typedef H225_GatekeeperConfirm Type;
};
template<> struct RasType<H225_RasMessage::e_gatekeeperReject> {
	typedef H225_GatekeeperReject Type;
};

然后,定义TagInfo,真正关联起一个tag值和它对应的类型。在其内部定义重定义出了类型Tag和Type,以及枚举值tag和flag。

template<int I> struct TagInfo {
	typedef RasTag<I> Tag;
	typedef typename RasType<I>::Type Type;
	enum {
		tag = I,
		// there are just 32 types of RAS, lucky!
		flag = (1 << I)
	};
};

此外,对于一个请示,其响应通常是成功或拒绝,因此还多定义了一些比较方便使用的模板;但是这些模板的定义是有要求的,对于一个Request来说,其Comfirm响应和Reject响应的tag值刚好比Request请求大1和大2,那么为什么刚好是1和2这两个数值呢。其实,这里只是因为H225_RasMessage::Choices在枚举时,就是按这么顺序写的,如e_gatekeeperRequest=0,e_gatekeeperConfirm=1,e_gatekeeperReject=2;所以对于GRQ/GCF/GRJ的TagInfo,刚好就可以完成下面的RequestInfo和ConfirmInfo、RejectInfo的定义;因此,这里的三个模板定义,是gnugk在理解了H225_RasMessage的类型定义后,特殊化取巧的定义实现方式。

template<int I> struct RequestInfo : public TagInfo<I> {
	typedef RasTag<I+1> ConfirmTag;
	typedef RasTag<I+2> RejectTag;
	typedef typename RasType<I+1>::Type ConfirmType;
	typedef typename RasType<I+2>::Type RejectType;
};

template<int I> struct ConfirmInfo : public TagInfo<I> {
	typedef RasTag<I-1> RequestTag;
	typedef typename RasType<I-1>::Type RequestType;
};

template<int I> struct RejectInfo : public TagInfo<I> {
	typedef RasTag<I-2> RequestTag;
	typedef typename RasType<I-2>::Type RequestType;
};

最后,定义RasInfo,表示一个Ras请求和它所关联的响应。

template<class> struct RasInfo;

再接下来就是特化定义各具体的Ras消息的RasInfo消息了。主要是分为4种类型:RAS request、RAS confirm、RAS reject和others。

理解了这里的定义后,再回过头来看,前面Creator的构造函数,Creator() : RasCreator(RasInfo::tag) { },就可以理解RasInfo::tag实际上表示的就是某一个Ras消息具体的H225_RasMessage::Choices所枚举的值。

三、RAS消息完整处理流程

这里,我们从头开始,梳理一遍,RAS消息的处理流程。
首先,在RasServer::Run执行时,注册各类RAS消息。

	RasPDU<H225_GatekeeperRequest>::Creator GRQCreator;
	RasPDU<H225_GatekeeperConfirm>::Creator GCFCreator;
	RasPDU<H225_GatekeeperReject>::Creator GRJCreator;
	RegistrationRequestPDU::Creator RRQCreator;
	RasPDU<H225_RegistrationConfirm>::Creator RCFCreator;
	RasPDU<H225_RegistrationReject>::Creator RRJCreator;
	RasPDU<H225_UnregistrationRequest>::Creator URQCreator;
	RasPDU<H225_UnregistrationConfirm>::Creator UCFCreator;
	RasPDU<H225_UnregistrationReject>::Creator URJCreator;
	AdmissionRequestPDU::Creator ARQCreator;
	RasPDU<H225_AdmissionConfirm>::Creator ACFCreator;
	RasPDU<H225_AdmissionReject>::Creator ARJCreator;
	RasPDU<H225_BandwidthRequest>::Creator BRQCreator;
	RasPDU<H225_BandwidthConfirm>::Creator BCFCreator;
	RasPDU<H225_BandwidthReject>::Creator BRJCreator;
	RasPDU<H225_DisengageRequest>::Creator DRQCreator;
	RasPDU<H225_DisengageConfirm>::Creator DCFCreator;
	RasPDU<H225_DisengageReject>::Creator DRJCreator;
	RasPDU<H225_LocationRequest>::Creator LRQCreator;
	RasPDU<H225_LocationConfirm>::Creator LCFCreator;
	RasPDU<H225_LocationReject>::Creator LRJCreator;
	RasPDU<H225_InfoRequest>::Creator IRQCreator;
	RasPDU<H225_InfoRequestResponse>::Creator IRRCreator;
	RasPDU<H225_UnknownMessageResponse>::Creator UMRCreator;
	RasPDU<H225_RequestInProgress>::Creator RIPCreator;
	RasPDU<H225_ResourcesAvailableIndicate>::Creator RAICreator;
	RasPDU<H225_ServiceControlIndication>::Creator SCICreator;
	RasPDU<H225_ServiceControlResponse>::Creator SCRCreator;
	RasPDU<H225_NonStandardMessage>::Creator NonStandardCreator;

其次,启动RAS监听后,在收到RAS消息时,会进入RasServer::ReadSocket(如果不清楚gnugk的网络结构的,可以查看网络监听章节的分析);通过RasListener::ReadRas读取相应的RAS消息,生成GatekeeperMessage实例;再通过 RasServer::CreateRasJob,提交给一个线程去异步执行,或者直接同步执行。

void RasServer::CreateRasJob(GatekeeperMessage * msg, bool syncronous)
{
	# 定义Ras的工厂类型,从RasPDU定义,可以知道该工厂的产品是RasMsg,产品标识是unsigned,也就是具体ras消息的tag值
	typedef Factory<RasMsg, unsigned> RasFactory;
	unsigned tag = msg->GetTag();
	PWaitAndSignal rlock(requests_mutex);
	PWaitAndSignal hlock(handlers_mutex);
	# 通过工厂方法,创建RasMsg的实例ras,之所以能知道每个具体的tag值对应的RasMsg是什么,是因为前面在RasServer::Run时,已经注册了;
	# 并且创建时需要传递GatekeeperMessage *参数,这个是由RasPDU约定的
	if (RasMsg *ras = RasFactory::Create(tag, msg)) {
		# 这里的RasServer::handlers成员,主要是用于gnugk的neighbor/parent关系的,这里先不讲解这部分功能。因此,iter == handlers.end()成立。
		std::list<RasHandler *>::iterator iter = find_if(handlers.begin(), handlers.end(), bind2nd(mem_fun(&RasHandler::IsExpected), ras));
		if (iter == handlers.end()) {
			std::list<RasMsg *>::iterator i = find_if(requests.begin(), requests.end(), bind2nd(mem_fun(&RasMsg::EqualTo), ras));
			# 这里作个判断,如何是重复的包,则忽略不处理。
			if (i != requests.end() && !(*i)->IsDone()) {
				PTRACE(2, "RAS\tDuplicate " << msg->GetTagName() << ", deleted");
				delete ras;
				ras = NULL;
			} else {
				# 若不是重复的包,则依赖是否要同步处理,走不同流程。
				if (syncronous) {
					# 若需要同步处理,则直接调用Exec方法,前面分析了RasMsg继承自Task,所以调用Exec就是直接进行Task处理。
					ras->Exec();
					delete ras;
					ras = NULL;
				} else {
					requests.push_back(ras);
					# 若需要异步处理,则把这个Task提交给Jobs实例,调用Jobs的Execute方法,启动多线程处理。
					# 提交给Jobs,是gnugk的多线程框架的定义,不清楚的,可以查看gnugk多线程分析的章节
					Job *job = new Jobs(ras);
					job->SetName(msg->GetTagName());
					job->Execute();
				}
			}
		} else {
			PTRACE(2, "RAS\tTrapped " << msg->GetTagName());
			// re-create RasMsg object by the handler
			ras = (*iter)->CreatePDU(ras);
			(*iter)->Process(ras);
		}
	} else {
		PTRACE(1, "RAS\tUnknown RAS message " << msg->GetTagName());
		delete msg;
	}
}

然后,执行到RasMsg::Exec的方法中,调用Process方法进行具体的处理。
这里的Process方法就是各RAS消息,通过RasPDU类来实现的。

template<> bool RasPDU<H225_GatekeeperRequest>::Process()
bool RegistrationRequestPDU::Process()
bool AdmissionRequestPDU::Process()
template<> bool RasPDU<H225_UnregistrationRequest>::Process()
template<> bool RasPDU<H225_BandwidthRequest>::Process()
template<> bool RasPDU<H225_DisengageRequest>::Process()
template<> bool RasPDU<H225_LocationRequest>::Process()
template<> bool RasPDU<H225_InfoRequestResponse>::Process()
template<> bool RasPDU<H225_ResourcesAvailableIndicate>::Process()
template<> bool RasPDU<H225_ServiceControlIndication>::Process()
template<> bool RasPDU<H225_ServiceControlResponse>::Process()
template<> bool RasPDU<H225_RegistrationReject>::Process()

最后,在处理完成后,经RasMsg::Reply方法通过GatekeeperMessage::Reply调用RasListener::SendRas将响应消息发送出去。至些,一个RAS从读取到处理再到发送响应的过程完成。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
基于C++&OPENCV 的全景图像拼接 C++是一种广泛使用的编程语言,它是由Bjarne Stroustrup于1979年在新泽西州美利山贝尔实验室开始设计开发的。C++是C语言的扩展,旨在提供更强大的编程能力,包括面向对象编程和泛型编程的支持。C++支持数据封装、继承和多态等面向对象编程的特性和泛型编程的模板,以及丰富的标准库,提供了大量的数据结构和算法,极大地提高了开发效率。12 C++是一种静态类型的、编译式的、通用的、大小写敏感的编程语言,它综合了高级语言和低级语言的特点。C++的语法与C语言非常相似,但增加了许多面向对象编程的特性,如类、对象、封装、继承和多态等。这使得C++既保持了C语言的低级特性,如直接访问硬件的能力,又提供了高级语言的特性,如数据封装和代码重用。13 C++的应用领域非常广泛,包括但不限于教育、系统开发、游戏开发、嵌入式系统、工业和商业应用、科研和高性能计算等领域。在教育领域,C++因其结构化和面向对象的特性,常被选为计算机科学和工程专业的入门编程语言。在系统开发领域,C++因其高效性和灵活性,经常被作为开发语言。游戏开发领域中,C++由于其高效性和广泛应用,在开发高性能游戏和游戏引擎中扮演着重要角色。在嵌入式系统领域,C++的高效和灵活性使其成为理想选择。此外,C++还广泛应用于桌面应用、Web浏览器、操作系统、编译器、媒体应用程序、数据库引擎、医疗工程和机器人等领域。16 学习C++的关键是理解其核心概念和编程风格,而不是过于深入技术细节。C++支持多种编程风格,每种风格都能有效地保证运行时间效率和空间效率。因此,无论是初学者还是经验丰富的程序员,都可以通过C++来设计和实现新系统或维护旧系统。3
根据提供的引用内容,似乎是RSA加密算法,而不是RAS加密算法。以下是Python实现RSA加密算法的步骤和代码: 1. 生成公钥和私钥 ```python import random def gcd(a, b): while b != 0: a, b = b, a % b return a def multiplicative_inverse(e, phi): d = 0 x1 = 0 x2 = 1 y1 = 1 temp_phi = phi while e > 0: temp1 = temp_phi // e temp2 = temp_phi - temp1 * e temp_phi = e e = temp2 x = x2 - temp1 * x1 y = d - temp1 * y1 x2 = x1 x1 = x d = y1 y1 = y if temp_phi == 1: return d + phi def generate_keypair(p, q): n = p * q phi = (p-1) * (q-1) e = random.randrange(1, phi) g = gcd(e, phi) while g != 1: e = random.randrange(1, phi) g = gcd(e, phi) d = multiplicative_inverse(e, phi) return ((e, n), (d, n)) ``` 2. 加密和解密 ```python def encrypt(pk, plaintext): key, n = pk cipher = [pow(ord(char), key, n) for char in plaintext] return cipher def decrypt(pk, ciphertext): key, n = pk plain = [chr(pow(char, key, n)) for char in ciphertext] return ''.join(plain) ``` 3. 使用示例 ```python p = 61 q = 53 public_key, private_key = generate_keypair(p, q) print("Public key: ", public_key) print("Private key: ", private_key) message = "Hello, World!" encrypted_message = encrypt(public_key, message) print("Encrypted message: ", ''.join(map(lambda x: str(x), encrypted_message))) decrypted_message = decrypt(private_key, encrypted_message) print("Decrypted message: ", decrypted_message) ``` 输出: ``` Public key: (1913, 3233) Private key: (1783, 3233) Encrypted message: 246811111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值