我想实现一个Microsoft CryptographicServiceProvider库,目前我正在考虑如何处理我创建的上下文句柄的最佳方法。
我的问题是针对这种情况的,但设计方法可以用于其他情况。
我来自托管代码背景,而且我对C / C ++中的多线程指针处理不是百分之百。
一般来说,有两个函数负责句柄的创建和销毁(CryptAcquireContext,CryptReleaseContext),所有后续的CSP函数都使用由创建者函数返回的句柄。
我没有找到微软的任何具体信息或规范,它提供了一种设计方法或规则。但我与微软创建的其他CSP提供商进行了研究,以找出设计规则,即:
其他MS CSP Provider会将有效指针作为句柄返回,否则返回NULL。
我不认为调用应用程序会传递完整的垃圾,但是它可能会传递一个已经释放的句柄,我的库应该返回错误。
这让我有三个想法如何实现:
只需使用malloc或new分配我的上下文结构的内存,并将原始指针作为句柄返回。
我可以预期调用我的库的应用程序将传递一个有效的句柄。但如果不是我的库将遇到一个未定义的行为。所以我需要一个更好的解决方案。
将我创建的指针添加到列表中(std :: list,std :: map)。所以我可以迭代列表来检查指针是否存在。对列表的访问受到互斥锁的保护。
这应该是安全的,并且常规的API使用不应该是性能问题。但在终端服务器方案中它可能是。在这种情况下,Windows进程lsass.exe为每个想要在单独线程中登录CSP上下文的用户创建,并为每个上下文进行大约10次API调用。
设计目标是我的库应该能够并行处理300个客户端。在这种情况下,我不知道Windows创建了多少个线程。
因此,如果可能的话,我更喜欢无锁实现。
我分配一个基本结构,它包含一个检查值和实际数据的指针。使用此结构的指针作为上下文句柄。
typedef struct CSPHandle
{
int Type; // (eg. magic number CSPContext=0xA1B2C3D4)
CSPContextPtr pCSPContext;
};
所以我可以读取传递指针的第一个字节,并检查数据是否等于我定义的类型。我对实际数据指针有完全的控制权,如果上下文被释放则设置为NULL。这是好主意还是坏主意?
您对此案有何看法?我应该采用其中一种方法还是有其他解决方案?
由于
答案 0 :(得分:0)
我找到了解决方案,并将回答我的问题。
我忽略了一点但很重要的细节
在CSP中,没有对dll的直接API调用(加载库,获取函数指针,调用函数),因为函数调用由Microsoft CSP转发,后者按名称加载CSP库。
因此Microsoft CSP需要知道并检查传递的上下文以获得到特定库的正确映射。
例:
1. client-> cryptacquirecontext( in cspname, out ctx)
2. MS CSP->从cspname中加载libray
3. MS CSP->调用已加载库的函数指针
4. CSP LIB-> cryptacquirecontext创建新的上下文
5. MS CSP->接收返回的csp句柄并将其保存到dll映射
6. MS CSP->将结果返回给调用应用程序
7. client-> cryptsetprovparam(ctx)//在之前创建的
8. MS CSP->检查上下文是否存在以及哪个库负责
9. MS CSP->如果给定的上下文无法映射到csp dll,则会返回错误,因为MS CSP不知道应该调用哪个函数指针。
所以在这种情况下,分配内存就足够了。如果客户端应用程序传递了无效的上下文句柄,它将永远不会访问csp库。
我认为MS CSP使用带有互斥锁的列表来存储上下文映射。因为上下文可以是从随机数到有效指针的任何内容。