我想实现一个Microsoft CryptographicServiceProvider库,目前正在考虑如何处理创建的上下文句柄的最佳方法。
我的问题是针对这种情况的,但是设计方法可以在其他情况下使用。
我来自托管代码背景,我对C / C ++中的多线程指针处理不满意。
通常,有两个函数负责句柄的创建和销毁(CryptAcquireContext,CryptReleaseContext),并且所有后续CSP函数都使用由创建者函数返回的句柄。
我没有找到Microsoft提供的任何具体信息或规范,这些信息或规范没有提供设计方法或规则来实现此目的。但是我与Microsoft创建的其他CSP提供程序进行了研究,以找出设计规则,这些规则是:
函数必须是线程安全的
上下文句柄不会在线程之间共享
如果上下文句柄无效,则返回错误
其他MS CSP提供程序将返回有效的指针作为句柄,否则返回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。这是一个好主意还是坏的主意?
您对此案有何看法?我应该采用其中一种方法还是有其他解决方案?
谢谢
最佳答案
我找到了解决方案,将回答我的问题。
我忽略了一点但很重要的细节
在CSP中,没有直接对dll的API调用(加载库,获取函数指针,调用函数),因为该函数调用是由Microsoft CSP转发的,该Microsoft CSP按名称加载了CSP库。
因此,Microsoft CSP需要知道并检查传递的上下文,以获取到特定库的正确映射。
例:
1. client-> cryptacquirecontext(在cspname中,输出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使用带有互斥保护的列表来存储上下文映射。因为上下文可以是从随机数到有效指针的任何内容。
关于c++ - 检查指针句柄是否有效,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/28859065/