用户自定义结构数据与VARIANT转换 .

时间:2024-10-12 13:34:19

用户自定义结构数据与VARIANT转换

cheungmine

将用户自定义的C结构数据存储成VARIANT类型,需要时再将VARIANT类型转为用户自定义的结构数据,有十分现实的意义,既然我们不想为这样的结构数据写一个COM包装类。虽然有很多方法和手段生成这样的VARIANT,但是,多数时候可能需要一个更加简单的,灵活的方法。我在做远程过程调用的C接口时,忽然联想到,既然RPC可以把任何数据以字节的形式发送,那么,就可以利用这个机制,把结构打包成字节数组。而字节数据是可以很方便地存储在VARIANT中。

这个过程是广为人知的,但是,真正把结构列集成字节数组,如果不想使用某些标称的序列化的方法,而全部自己写,的确要费一番功夫。不是

技术有多难,是很繁琐。我把前2年写的代码翻出来,简单调用一下,就有了这篇文章。采用我的方法,C/C++程序员可以把自己定义的结构放到VARIANT、CComVariant、COleVariant等各种VARIANT中,也可以反向转换。而VARIANT是可以很方便地在COM接口中传递。这样,就多了一种在自动化COM接口中传递自定义结构的手段。

不多说废话,全部内容见下面的代码,我还会上传整个工程。

struct2variant.cpp 如下:

  1. ///////////////////////////////////////////////////////////////////////
  2. // struct2variant.cpp
  3. // cheungmine@gmail.com
  4. // 2010-6
  5. // 下面的程序演示了如何在用户自定义的结构和VARIANT类型之间转换
  6. // 保留所有权利
  7. //
  8. #include "stdafx.h"
  9. #include "rpc/rpcapi.h"
  10. #include <assert.h>
  11. #ifdef _DEBUG
  12. #  pragma comment(lib, "rpc/rpclib/debug/rpclib.lib")
  13. #else
  14. #  pragma comment(lib, "rpc/rpclib/release/rpclib.lib")
  15. #endif
  16. // 自定义结构标识
  17. #define MY_STRUCT_ID  101   // 标识结构的任意数字
  18. typedef struct _PointF
  19. {
  20. double x;
  21. double y;
  22. }PointF;
  23. // 自定义结构
  24. typedef struct _MyStruct
  25. {
  26. CHAR      id[32];
  27. CHAR      server[130];
  28. CHAR      instance[10];
  29. CHAR      userid[32];
  30. BOOL      isdraw;
  31. ULONG     token;
  32. LONG      timeout;
  33. LONG      keepalive;
  34. LONG      reserved;
  35. BOOL      status;
  36. LONG      capacity;
  37. LONG volatile counter;
  38. // 说明如何保存变长数组
  39. SHORT     numPts;
  40. PointF   *ptArray;
  41. }MyStruct;
  42. void PrintfMyStruct(const char *desc, MyStruct *data)
  43. {
  44. printf("==========%s==========/n", desc);
  45. printf("id=%s/n", data->id);
  46. printf("server=%s/n", data->server);
  47. printf("instance=%s/n", data->instance);
  48. printf("userid=%s/n", data->userid);
  49. printf("isdraw=%d/n", data->isdraw);
  50. printf("token=%d/n", data->token);
  51. printf("timeout=%d/n", data->timeout);
  52. printf("keepalive=%d/n", data->keepalive);
  53. printf("reserved=%d/n", data->reserved);
  54. printf("status=%d/n", data->status);
  55. printf("capacity=%d/n", data->capacity);
  56. printf("counter=%d/n", data->counter);
  57. printf("numPts=%d/n", data->numPts);
  58. for(int i=0; i<data->numPts; i++)
  59. printf("ptArray[%d]= (x=%.3lf,     y=%.3lf)/n", i, data->ptArray[i].x, data->ptArray[i].y);
  60. }
  61. static HRESULT CreateStreamFromBytes(BYTE *inBytes, DWORD cbSize, IStream **ppStm)
  62. {
  63. HGLOBAL hGlobal = GlobalAlloc(GMEM_MOVEABLE, 0);
  64. ATLASSERT(hGlobal);
  65. if (!hGlobal)
  66. return E_OUTOFMEMORY;
  67. CComPtr<IStream> spStm;
  68. HRESULT hr = CreateStreamOnHGlobal(hGlobal, TRUE, &spStm);
  69. ATLASSERT(hr == S_OK);
  70. if (hr != S_OK || spStm == 0){
  71. GlobalFree(hGlobal);
  72. return hr;
  73. }
  74. ULONG  ulWritten = 0;
  75. hr = spStm->Write(inBytes, cbSize, &ulWritten);
  76. if (hr != S_OK || ulWritten != cbSize)
  77. return E_FAIL;
  78. return spStm.CopyTo(ppStm);
  79. }
  80. ////////////////////////////////////////////////////////////////////
  81. // 列集自定义数据到VARIANT
  82. //
  83. static void MarshallMyStruct(MyStruct *inData, VARIANT *outVar)
  84. {
  85. assert(inData && outVar);
  86. rpc_invoke_descriptor  inv  = {0};
  87. rpc_invoke_init(&inv, MY_STRUCT_ID, 14);    // 14个参数
  88. // 下面每个结构成员参数都需要按次序绑定
  89. rpc_invoke_bind_param(&inv,
  90. 0,                    /* 结构成员参数索引0-based */
  91. RPCT_STRING,          /* 指明字符串数组类型 */
  92. (void*)inData->id,     /* 指向实际数据的指针 */
  93. strlen(inData->id)+1, /* 只需要保存有效的数据 */
  94. 0                     /*0 表示我们不具有id的所有权(不负责释放内存) */
  95. );
  96. rpc_invoke_bind_param(&inv,
  97. 1,
  98. RPCT_STRING,
  99. (void*)inData->server,
  100. strlen(inData->server)+1,
  101. 0
  102. );
  103. rpc_invoke_bind_param(&inv,
  104. 2,
  105. RPCT_STRING,
  106. (void*)inData->instance,
  107. strlen(inData->instance)+1,
  108. 0
  109. );
  110. rpc_invoke_bind_param(&inv,
  111. 3,
  112. RPCT_STRING,
  113. (void*)inData->userid,
  114. strlen(inData->userid)+1,
  115. 0
  116. );
  117. rpc_invoke_bind_param(&inv,
  118. 4,
  119. RPCT_BOOL,
  120. (void*) &inData->isdraw,
  121. 0,  /* 不是数组, 为0 */
  122. 0
  123. );
  124. rpc_invoke_bind_param(&inv,
  125. 5,
  126. RPCT_ULONG,
  127. (void*) &inData->token,
  128. 0,
  129. 0
  130. );
  131. rpc_invoke_bind_param(&inv,
  132. 6,
  133. RPCT_LONG,
  134. (void*) &inData->timeout,
  135. 0,
  136. 0
  137. );
  138. rpc_invoke_bind_param(&inv,
  139. 7,
  140. RPCT_LONG,
  141. (void*) &inData->keepalive,
  142. 0,
  143. 0
  144. );
  145. rpc_invoke_bind_param(&inv,
  146. 8,
  147. RPCT_LONG,
  148. (void*) &inData->reserved,
  149. 0,
  150. 0
  151. );
  152. rpc_invoke_bind_param(&inv,
  153. 9,
  154. RPCT_BOOL,
  155. (void*) &inData->status,
  156. 0,
  157. 0
  158. );
  159. rpc_invoke_bind_param(&inv,
  160. 10,
  161. RPCT_LONG,
  162. (void*) &inData->capacity,
  163. 0,
  164. 0
  165. );
  166. rpc_invoke_bind_param(&inv,
  167. 11,
  168. RPCT_LONG,
  169. (void*) &inData->counter,
  170. 0,
  171. 0
  172. );
  173. rpc_invoke_bind_param(&inv,
  174. 12,
  175. RPCT_SHORT,
  176. (void*) &inData->numPts,
  177. 0,
  178. 0
  179. );
  180. rpc_invoke_bind_param(&inv,
  181. 13,
  182. RPCT_DOUBLE,    /* 简单结构的成员类型 */
  183. (void*) inData->ptArray, /* 内存结构=[x1,y1,x2,y2,...,xn,yn], 千万不可写成:(void*) &inData->ptArray */
  184. inData->numPts * (sizeof(PointF)/sizeof(double)), /* double类型成员的数目=点数x2 */
  185. 0
  186. );
  187. /* 计算调用消息的字节总数 */
  188. dword_t cbOut = rpc_invoke_get_size(&inv);
  189. char *outBuf = (char*) malloc(cbOut);
  190. /* 列集全部数据到totalBuf中 */
  191. rpc_invoke_marshal(&inv, outBuf, cbOut);
  192. //////////////////////////////////////////////////////////
  193. // 到此,我们已经在outBuf中保存了结构的全部数据,
  194. // 下面把数据转换成IStream进而转换成VARIANT
  195. CComPtr<IStream> spStm;
  196. CreateStreamFromBytes((BYTE*)outBuf, cbOut, &spStm);
  197. VariantInit(outVar);
  198. outVar->vt = VT_UNKNOWN;
  199. outVar->punkVal = (IUnknown*) spStm.Detach();
  200. free(outBuf);
  201. rpc_invoke_clear_all(&inv);
  202. }
  203. ////////////////////////////////////////////////////////////////////
  204. // 散集VARIANT到自定义数据
  205. //
  206. static void UnmarshallMyStruct(VARIANT *inVar, MyStruct *outData)
  207. {
  208. assert(inVar && outData);
  209. assert(inVar->vt==VT_UNKNOWN && inVar->punkVal);
  210. HGLOBAL  hGlobal = 0;
  211. HRESULT hr = GetHGlobalFromStream((IStream*)inVar->punkVal, &hGlobal);
  212. assert(hr==S_OK);
  213. size_t  cbData = GlobalSize(hGlobal);
  214. char   *pbData = (char*) GlobalLock(hGlobal);
  215. char   *rpcHdr = pbData;
  216. assert(cbData >= RPC_INVOKE_HEADER_SIZE);
  217. assert(rpcHdr[0]=='R' && rpcHdr[1]=='C');
  218. rpc_invoke_descriptor  inv={0};
  219. rpc_invoke_init(&inv, 0, 0);
  220. inv.encPkg = rpcHdr[2];
  221. inv.encHdr = rpcHdr[3];
  222. assert (inv.encHdr == 0);
  223. inv.ordinal = word_ntoh(*((word_t*)(rpcHdr+20)));               // 方法序号: MY_STRUCT_ID
  224. assert(inv.ordinal == MY_STRUCT_ID);
  225. inv.invToken = dword_ntoh(*((dword_t*)(rpcHdr+4)));             // 用户标识
  226. inv.totalBytes = dword_ntoh(*((dword_t*)(rpcHdr+8)));           // 总消息字节数(也许是压缩的)
  227. inv.bitsFlag = word_ntoh(*((word_t*)(rpcHdr+12)));              // 标志
  228. inv.bigEndian = GET_BIT(inv.bitsFlag, RPC_BIGENDIAN_BIT);       // 客户方列集的字节次序
  229. inv.reserved = word_ntoh(*((word_t*)(rpcHdr+14)));              // 保留值
  230. inv.result = dword_ntoh(*((dword_t*)(rpcHdr+16)));              // 返回值
  231. inv.num_params = word_ntoh(*((word_t*)(rpcHdr+22)));            // 参数数目
  232. rpc_invoke_error  err={0};
  233. rpc_invoke_unmarshal(&inv, rpcHdr, inv.totalBytes, &inv.params_list, &inv.num_params, &err);
  234. GlobalUnlock(hGlobal);
  235. strncpy_s(outData->id, sizeof(outData->id), (char*) inv.params_list[0].param_bytes, sizeof(outData->id)-1);
  236. strncpy_s(outData->server, sizeof(outData->server), (char*) inv.params_list[1].param_bytes, sizeof(outData->server)-1);
  237. strncpy_s(outData->instance, sizeof(outData->instance), (char*) inv.params_list[2].param_bytes, sizeof(outData->instance)-1);
  238. strncpy_s(outData->userid, sizeof(outData->userid), (char*) inv.params_list[3].param_bytes, sizeof(outData->userid)-1);
  239. outData->isdraw = PARAMVALUE(inv.params_list, 4, BOOL);
  240. outData->token = PARAMVALUE(inv.params_list, 5, ULONG);
  241. outData->timeout = PARAMVALUE(inv.params_list, 6, LONG);
  242. outData->keepalive = PARAMVALUE(inv.params_list, 7, LONG);
  243. outData->reserved = PARAMVALUE(inv.params_list, 8, LONG);
  244. outData->status = PARAMVALUE(inv.params_list, 9, BOOL);
  245. outData->capacity = PARAMVALUE(inv.params_list, 10, LONG);
  246. outData->counter = PARAMVALUE(inv.params_list, 11, LONG);
  247. outData->numPts = PARAMVALUE(inv.params_list, 12, SHORT);
  248. // 为输出分配 ptArray
  249. outData->ptArray = (PointF*) malloc(sizeof(PointF)*outData->numPts);
  250. memcpy(outData->ptArray, inv.params_list[13].param_bytes, sizeof(PointF)*outData->numPts);
  251. rpc_invoke_clear_all(&inv);
  252. }
  253. int main(int argc, CHAR* argv[])
  254. {
  255. MyStruct     data, data2;
  256. CComVariant  var;   // 这个var 可以存储在任何需要使用到的地方
  257. // 初始化结构data
  258. strcpy_s(data.id, sizeof(data.id), "13890");
  259. strcpy_s(data.server, sizeof(data.server), "localhost");
  260. strcpy_s(data.instance, sizeof(data.instance), "port:6755");
  261. strcpy_s(data.userid, sizeof(data.userid), "cheungmine");
  262. data.isdraw = 1;
  263. data.token = 54321;
  264. data.timeout = 3000;
  265. data.keepalive = 6500;
  266. data.reserved=0;
  267. data.status = 0;
  268. data.capacity = 4096;
  269. data.counter = 99;
  270. data.numPts = 16;
  271. data.ptArray = (PointF*) malloc(data.numPts*sizeof(PointF));
  272. for(int i=0; i<data.numPts; i++){
  273. data.ptArray[i].x = 100+i;
  274. data.ptArray[i].y = 200+i;
  275. }
  276. PrintfMyStruct("input MyStruct", &data);
  277. // 用户的结构转换为VARIANT: data=>var
  278. MarshallMyStruct(&data, &var);
  279. free(data.ptArray);
  280. // ...使用var
  281. // VARIANT转为用户的结构: var=>data
  282. UnmarshallMyStruct(&var, &data2);
  283. PrintfMyStruct("output MyStruct", &data2);
  284. free(data2.ptArray);
  285. }

///////////////////////////////////////////////////////////////////////
// struct2variant.cpp
// cheungmine@gmail.com
// 2010-6
// 下面的程序演示了如何在用户自定义的结构和VARIANT类型之间转换
// 保留所有权利
//
#include "stdafx.h"
#include "rpc/rpcapi.h"
#include <assert.h>
#ifdef _DEBUG
# pragma comment(lib, "rpc/rpclib/debug/rpclib.lib")
#else
# pragma comment(lib, "rpc/rpclib/release/rpclib.lib")
#endif
// 自定义结构标识
#define MY_STRUCT_ID 101 // 标识结构的任意数字
typedef struct _PointF
{
double x;
double y;
}PointF;
// 自定义结构
typedef struct _MyStruct
{
CHAR id[32];
CHAR server[130];
CHAR instance[10];
CHAR userid[32];
BOOL isdraw;
ULONG token;
LONG timeout;
LONG keepalive;
LONG reserved;
BOOL status;
LONG capacity;
LONG volatile counter;
// 说明如何保存变长数组
SHORT numPts;
PointF *ptArray;
}MyStruct;
void PrintfMyStruct(const char *desc, MyStruct *data)
{
printf("==========%s==========/n", desc);
printf("id=%s/n", data->id);
printf("server=%s/n", data->server);
printf("instance=%s/n", data->instance);
printf("userid=%s/n", data->userid);
printf("isdraw=%d/n", data->isdraw);
printf("token=%d/n", data->token);
printf("timeout=%d/n", data->timeout);
printf("keepalive=%d/n", data->keepalive);
printf("reserved=%d/n", data->reserved);
printf("status=%d/n", data->status);
printf("capacity=%d/n", data->capacity);
printf("counter=%d/n", data->counter);
printf("numPts=%d/n", data->numPts);
for(int i=0; i<data->numPts; i++)
printf("ptArray[%d]= (x=%.3lf, y=%.3lf)/n", i, data->ptArray[i].x, data->ptArray[i].y);
}
static HRESULT CreateStreamFromBytes(BYTE *inBytes, DWORD cbSize, IStream **ppStm)
{
HGLOBAL hGlobal = GlobalAlloc(GMEM_MOVEABLE, 0);
ATLASSERT(hGlobal);
if (!hGlobal)
return E_OUTOFMEMORY;

CComPtr<IStream> spStm;
HRESULT hr = CreateStreamOnHGlobal(hGlobal, TRUE, &spStm);
ATLASSERT(hr == S_OK);
if (hr != S_OK || spStm == 0){
GlobalFree(hGlobal);
return hr;
}

ULONG ulWritten = 0;
hr = spStm->Write(inBytes, cbSize, &ulWritten);
if (hr != S_OK || ulWritten != cbSize)
return E_FAIL;
return spStm.CopyTo(ppStm);
}
////////////////////////////////////////////////////////////////////
// 列集自定义数据到VARIANT
//
static void MarshallMyStruct(MyStruct *inData, VARIANT *outVar)
{
assert(inData && outVar);
rpc_invoke_descriptor inv = {0};
rpc_invoke_init(&inv, MY_STRUCT_ID, 14); // 14个参数
// 下面每个结构成员参数都需要按次序绑定
rpc_invoke_bind_param(&inv,
0, /* 结构成员参数索引0-based */
RPCT_STRING, /* 指明字符串数组类型 */
(void*)inData->id, /* 指向实际数据的指针 */
strlen(inData->id)+1, /* 只需要保存有效的数据 */
0 /*0 表示我们不具有id的所有权(不负责释放内存) */
);
rpc_invoke_bind_param(&inv,
1,
RPCT_STRING,
(void*)inData->server,
strlen(inData->server)+1,
0
);
rpc_invoke_bind_param(&inv,
2,
RPCT_STRING,
(void*)inData->instance,
strlen(inData->instance)+1,
0
);
rpc_invoke_bind_param(&inv,
3,
RPCT_STRING,
(void*)inData->userid,
strlen(inData->userid)+1,
0
);
rpc_invoke_bind_param(&inv,
4,
RPCT_BOOL,
(void*) &inData->isdraw,
0, /* 不是数组, 为0 */
0
);
rpc_invoke_bind_param(&inv,
5,
RPCT_ULONG,
(void*) &inData->token,
0,
0
);
rpc_invoke_bind_param(&inv,
6,
RPCT_LONG,
(void*) &inData->timeout,
0,
0
);
rpc_invoke_bind_param(&inv,
7,
RPCT_LONG,
(void*) &inData->keepalive,
0,
0
);
rpc_invoke_bind_param(&inv,
8,
RPCT_LONG,
(void*) &inData->reserved,
0,
0
);
rpc_invoke_bind_param(&inv,
9,
RPCT_BOOL,
(void*) &inData->status,
0,
0
);
rpc_invoke_bind_param(&inv,
10,
RPCT_LONG,
(void*) &inData->capacity,
0,
0
);
rpc_invoke_bind_param(&inv,
11,
RPCT_LONG,
(void*) &inData->counter,
0,
0
);
rpc_invoke_bind_param(&inv,
12,
RPCT_SHORT,
(void*) &inData->numPts,
0,
0
);
rpc_invoke_bind_param(&inv,
13,
RPCT_DOUBLE, /* 简单结构的成员类型 */
(void*) inData->ptArray, /* 内存结构=[x1,y1,x2,y2,...,xn,yn], 千万不可写成:(void*) &inData->ptArray */
inData->numPts * (sizeof(PointF)/sizeof(double)), /* double类型成员的数目=点数x2 */
0
);
/* 计算调用消息的字节总数 */
dword_t cbOut = rpc_invoke_get_size(&inv);
char *outBuf = (char*) malloc(cbOut);

/* 列集全部数据到totalBuf中 */
rpc_invoke_marshal(&inv, outBuf, cbOut);
//////////////////////////////////////////////////////////
// 到此,我们已经在outBuf中保存了结构的全部数据,
// 下面把数据转换成IStream进而转换成VARIANT
CComPtr<IStream> spStm;
CreateStreamFromBytes((BYTE*)outBuf, cbOut, &spStm);
VariantInit(outVar);
outVar->vt = VT_UNKNOWN;
outVar->punkVal = (IUnknown*) spStm.Detach();
free(outBuf);
rpc_invoke_clear_all(&inv);
}
////////////////////////////////////////////////////////////////////
// 散集VARIANT到自定义数据
//
static void UnmarshallMyStruct(VARIANT *inVar, MyStruct *outData)
{
assert(inVar && outData);
assert(inVar->vt==VT_UNKNOWN && inVar->punkVal);
HGLOBAL hGlobal = 0;
HRESULT hr = GetHGlobalFromStream((IStream*)inVar->punkVal, &hGlobal);
assert(hr==S_OK);
size_t cbData = GlobalSize(hGlobal);
char *pbData = (char*) GlobalLock(hGlobal);
char *rpcHdr = pbData;
assert(cbData >= RPC_INVOKE_HEADER_SIZE);
assert(rpcHdr[0]=='R' && rpcHdr[1]=='C');
rpc_invoke_descriptor inv={0};
rpc_invoke_init(&inv, 0, 0);
inv.encPkg = rpcHdr[2];
inv.encHdr = rpcHdr[3];
assert (inv.encHdr == 0);
inv.ordinal = word_ntoh(*((word_t*)(rpcHdr+20))); // 方法序号: MY_STRUCT_ID
assert(inv.ordinal == MY_STRUCT_ID);
inv.invToken = dword_ntoh(*((dword_t*)(rpcHdr+4))); // 用户标识
inv.totalBytes = dword_ntoh(*((dword_t*)(rpcHdr+8))); // 总消息字节数(也许是压缩的)
inv.bitsFlag = word_ntoh(*((word_t*)(rpcHdr+12))); // 标志
inv.bigEndian = GET_BIT(inv.bitsFlag, RPC_BIGENDIAN_BIT); // 客户方列集的字节次序
inv.reserved = word_ntoh(*((word_t*)(rpcHdr+14))); // 保留值
inv.result = dword_ntoh(*((dword_t*)(rpcHdr+16))); // 返回值
inv.num_params = word_ntoh(*((word_t*)(rpcHdr+22))); // 参数数目
rpc_invoke_error err={0};
rpc_invoke_unmarshal(&inv, rpcHdr, inv.totalBytes, &inv.params_list, &inv.num_params, &err);

GlobalUnlock(hGlobal);
strncpy_s(outData->id, sizeof(outData->id), (char*) inv.params_list[0].param_bytes, sizeof(outData->id)-1);
strncpy_s(outData->server, sizeof(outData->server), (char*) inv.params_list[1].param_bytes, sizeof(outData->server)-1);
strncpy_s(outData->instance, sizeof(outData->instance), (char*) inv.params_list[2].param_bytes, sizeof(outData->instance)-1);
strncpy_s(outData->userid, sizeof(outData->userid), (char*) inv.params_list[3].param_bytes, sizeof(outData->userid)-1);
outData->isdraw = PARAMVALUE(inv.params_list, 4, BOOL);
outData->token = PARAMVALUE(inv.params_list, 5, ULONG);
outData->timeout = PARAMVALUE(inv.params_list, 6, LONG);
outData->keepalive = PARAMVALUE(inv.params_list, 7, LONG);
outData->reserved = PARAMVALUE(inv.params_list, 8, LONG);
outData->status = PARAMVALUE(inv.params_list, 9, BOOL);
outData->capacity = PARAMVALUE(inv.params_list, 10, LONG);
outData->counter = PARAMVALUE(inv.params_list, 11, LONG);
outData->numPts = PARAMVALUE(inv.params_list, 12, SHORT);
// 为输出分配 ptArray
outData->ptArray = (PointF*) malloc(sizeof(PointF)*outData->numPts);
memcpy(outData->ptArray, inv.params_list[13].param_bytes, sizeof(PointF)*outData->numPts);
rpc_invoke_clear_all(&inv);
}
int main(int argc, CHAR* argv[])
{
MyStruct data, data2;
CComVariant var; // 这个var 可以存储在任何需要使用到的地方
// 初始化结构data
strcpy_s(data.id, sizeof(data.id), "13890");
strcpy_s(data.server, sizeof(data.server), "localhost");
strcpy_s(data.instance, sizeof(data.instance), "port:6755");
strcpy_s(data.userid, sizeof(data.userid), "cheungmine");
data.isdraw = 1;
data.token = 54321;
data.timeout = 3000;
data.keepalive = 6500;
data.reserved=0;
data.status = 0;
data.capacity = 4096;
data.counter = 99;
data.numPts = 16;
data.ptArray = (PointF*) malloc(data.numPts*sizeof(PointF));
for(int i=0; i<data.numPts; i++){
data.ptArray[i].x = 100+i;
data.ptArray[i].y = 200+i;
}
PrintfMyStruct("input MyStruct", &data);

// 用户的结构转换为VARIANT: data=>var
MarshallMyStruct(&data, &var);
free(data.ptArray);
// ...使用var
// VARIANT转为用户的结构: var=>data
UnmarshallMyStruct(&var, &data2);
PrintfMyStruct("output MyStruct", &data2);
free(data2.ptArray);
}

其中:rpcapi.h可以参考如下:

  1. /**
  2. * rpcapi.h -cheungmine@gmail.com
  3. * all rights reserved 2009
  4. */
  5. #ifndef _RPCAPI_H__
  6. #define _RPCAPI_H__
  7. #include <winsock2.h>
  8. #pragma comment(lib, "ws2_32.lib")
  9. #include <process.h>  /* _beginthreadex, _endthread */
  10. #include "../rc4/unistd.h"
  11. #include "../rc4/md5.h"
  12. #include "../rc4/rc4.h"
  13. #include "rpctype.h"
  14. #include "rpcerr.h"
  15. #ifdef __cplusplus
  16. extern "C" {
  17. #endif
  18. static BOOL  _rpc_is_bigendian = (('4321'>>24)=='1');
  19. #define PARAMVALUE(pl,i,type)     ((type)(*((type*) pl[i].param_bytes)))
  20. typedef enum
  21. {
  22. RPC_ENCHEADER_BIT  = 0,
  23. RPC_ENCPACKAGE_BIT  = 1,
  24. RPC_BIGENDIAN_BIT  = 7
  25. }RPC_BITFLAG_ENUM;
  26. /**
  27. * param descriptor
  28. */
  29. #define RPC_PARAM_HEADER_SIZE  16
  30. typedef struct _rpc_param_descriptor
  31. {
  32. word_t      param_type;         // 参数类型:变量类型或结构类型
  33. word_t      size_type;          // 参数类型尺寸字节
  34. size_t      array_size;         // 数组元素数目: 0 不是数组; >0数组
  35. size_t      param_size;         // 参数数据字节数=参数类型尺寸字节*元素数目
  36. void       *param_bytes;        // 指向参数数据的指针的引用, 不复制数据
  37. BOOL        is_owner;           // 是否拥有数据. 如果为TRUE, 需要free(param_bytes)
  38. }rpc_param_descriptor;
  39. /**
  40. * invoke descriptor
  41. */
  42. #define RPC_INVOKE_HEADER_SIZE  24      /* 不可以更改 */
  43. typedef struct _rpc_invoke_descriptor
  44. {
  45. /* 24字节头 + 内容
  46. *  ['RCmn'(4)|用户标识(4)|总消息字节(4)|标志(2)| 保留(2)|原始字节数(4)|方法序号(2)|参数数目(2)]
  47. */
  48. dword_t                totalBytes;  // 总消息字节4
  49. word_t                 bitsFlag;    // 标志位2: [7=BigEndian]
  50. word_t                 reserved;    // 保留2
  51. dword_t                result;      // 返回值
  52. // 内部值, 调用时,需要列集在bitsFlag中
  53. dword_t                invToken;
  54. byte                   bigEndian;
  55. byte                   encHdr;
  56. byte                   encPkg;
  57. // 如果压缩或加密, 从以下位置内容开始
  58. ushort                 ordinal;     // 方法序号2
  59. ushort                 num_params;  // 参数数目
  60. rpc_param_descriptor  *params_list; // 参数列表
  61. // 做为输入时, 存放临时值
  62. //
  63. char                  *pbBuf;
  64. union{
  65. char               bVal;
  66. long               lVal;
  67. short              sVal;
  68. float              fVal;
  69. double             dVal;
  70. __int64            llVal;
  71. };
  72. }rpc_invoke_descriptor;
  73. /**
  74. * connection descriptor
  75. */
  76. typedef struct _rpc_connection_descriptor
  77. {
  78. BOOL               is_bigendian;    // 字节顺序
  79. dword_t            token;           // 调用标识
  80. dword_t            timeout;         // 超时
  81. byte               enc_hdr;         // 头加密标志
  82. byte               enc_pkg;         // 参数包加密标志
  83. SOCKET             stream;          // SOCKET 连接
  84. char               host[130];       // 主机名或IP地址
  85. char               port[6];         // 端口号
  86. rpc_invoke_error   last_err;        // 最近的错误
  87. char               buffer[RPC_BUFFSIZE];  // 网络传输缓冲区
  88. }rpc_connection_descriptor;
  89. /*=============================================================================
  90. Private Functions
  91. host byte order and network byte order transform
  92. =============================================================================*/
  93. static int SafeStringSize(const char* psz)
  94. {
  95. return (int)(psz? (strlen(psz)+1):0);
  96. }
  97. /**
  98. * More fast than swap_bytes(...) for handle word and dword type
  99. */
  100. #define swap_word_type(x)  ((WORD)(((((WORD)(x))&0x00ff)<<8)|((((WORD)(x))&0xff00)>>8)))
  101. #define swap_dword_type(x)  ((DWORD)(((((DWORD)(x))&0xff000000)>>24)|((((DWORD)(x))&0x00ff0000)>>8)|((((DWORD)(x))&0x0000ff00)<<8)|((((DWORD)(x))&0x000000ff)<<24)))
  102. static void swap_bytes(void *wordP, size_t cbSize /*must be 2, 4, 8 */)
  103. {
  104. size_t   i;
  105. byte     t;
  106. for(i=0; i<cbSize/2; i++){
  107. t = ((byte *) wordP)[i];
  108. ((byte *)wordP)[i] = ((byte *) wordP)[cbSize-i-1];
  109. ((byte *) wordP)[cbSize-i-1] = t;
  110. }
  111. }
  112. static dword_t  dword_hton(dword_t host)
  113. {
  114. if (!_rpc_is_bigendian)
  115. host = swap_dword_type(host);
  116. return  host;
  117. }
  118. static dword_t  dword_ntoh(dword_t net)
  119. {
  120. if (!_rpc_is_bigendian)
  121. net = swap_dword_type(net);
  122. return  net;
  123. }
  124. static word_t   word_hton(word_t host)
  125. {
  126. if (!_rpc_is_bigendian)
  127. host = swap_word_type(host);
  128. return  host;
  129. }
  130. static word_t   word_ntoh(word_t net)
  131. {
  132. if (!_rpc_is_bigendian)
  133. net = swap_word_type(net);
  134. return  net;
  135. }
  136. static qword_t  qword_hton(qword_t host)
  137. {
  138. if (!_rpc_is_bigendian)
  139. swap_bytes(&host, sizeof(qword_t));
  140. return  host;
  141. }
  142. static qword_t  qword_ntoh(qword_t net)
  143. {
  144. if (!_rpc_is_bigendian)
  145. swap_bytes(&net, sizeof(qword_t));
  146. return  net;
  147. }
  148. static double   double_hton(double host)
  149. {
  150. if (!_rpc_is_bigendian)
  151. swap_bytes(&host, sizeof(qword_t));
  152. return  host;
  153. }
  154. static double   double_ntoh(double net)
  155. {
  156. if (!_rpc_is_bigendian)
  157. swap_bytes(&net, sizeof(qword_t));
  158. return  net;
  159. }
  160. static float    float_hton(float host)
  161. {
  162. if (!_rpc_is_bigendian)
  163. swap_bytes(&host, sizeof(dword_t));
  164. return  host;
  165. }
  166. static float    float_ntoh(float net)
  167. {
  168. if (!_rpc_is_bigendian)
  169. swap_bytes(&net, sizeof(dword_t));
  170. return  net;
  171. }
  172. /*=============================================================================
  173. Private Functions
  174. socket helper functions
  175. =============================================================================*/
  176. static int setbufsize(SOCKET s, int rcvlen /*RPC_BUFFSIZE*/, int sndlen /*RPC_BUFFSIZE*/)
  177. {
  178. int rcv, snd;
  179. int rcvl = (int) sizeof(int);
  180. int sndl = rcvl;
  181. if ( getsockopt(s, SOL_SOCKET, SO_RCVBUF, (char*)&rcv, &rcvl)==SOCKET_ERROR ||
  182. getsockopt(s, SOL_SOCKET, SO_SNDBUF, (char*)&snd, &sndl)==SOCKET_ERROR )
  183. return SOCKET_ERROR;
  184. if(rcv < rcvlen){
  185. rcv = rcvlen;
  186. rcvl = setsockopt(s, SOL_SOCKET, SO_RCVBUF, (char*)&rcv, rcvl);
  187. assert(rcvl==0);
  188. }
  189. if(snd < sndlen){
  190. snd = sndlen;
  191. sndl = setsockopt(s, SOL_SOCKET, SO_SNDBUF, (char*)&snd, sndl);
  192. assert(sndl==0);
  193. }
  194. return 0;
  195. }
  196. static int sendmsg(SOCKET s, const char* msgbuf, int msglen, int flags)
  197. {
  198. int ret;
  199. int offset = 0;
  200. int left = msglen;
  201. while (left > 0) {
  202. ret = send(s, &msgbuf[offset], left, flags);
  203. if (ret==SOCKET_ERROR || ret==0)
  204. return ret;
  205. left -= ret;
  206. offset += ret;
  207. }
  208. assert(offset==msglen);
  209. return offset;
  210. }
  211. static int recvmsg(SOCKET s, char* msgbuf, int buflen, int flags)
  212. {
  213. int     ret;
  214. int     offset = 0;
  215. int     left = buflen;
  216. while (left > 0){
  217. ret = recv(s, &msgbuf[offset], left, flags);
  218. if (ret==SOCKET_ERROR || ret==0)
  219. return ret;
  220. offset += ret;
  221. left -= ret;
  222. }
  223. assert(offset==buflen);
  224. return offset;
  225. }
  226. static BOOL sendbulk(SOCKET s, const char* data, int dataSize, int flags, int maxmsg)
  227. {
  228. int send, ret;
  229. int offset = 0;
  230. int left = dataSize;
  231. while (left > 0) {
  232. send = left>maxmsg? maxmsg:left;
  233. ret = sendmsg(s, &data[offset], send, flags);
  234. if (ret != send)
  235. return FALSE;
  236. offset += ret;
  237. left -= ret;
  238. }
  239. return TRUE;
  240. }
  241. static BOOL recvbulk(SOCKET s, char* buf, int recvlen, int flags, int maxmsg)
  242. {
  243. int  recv, ret;
  244. int  offset = 0;
  245. int  left = recvlen;
  246. while (left > 0){
  247. recv = left>maxmsg? maxmsg:left;
  248. ret = recvmsg(s, &buf[offset], recv, flags);
  249. if (ret != recv)
  250. return FALSE;
  251. offset += ret;
  252. left -= ret;
  253. }
  254. return TRUE;
  255. }
  256. static LPCSTR errmsg(DWORD dwCode, LPSTR lpszMsgBuf, DWORD dwMsgBufBytes)
  257. {
  258. FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,
  259. NULL, dwCode, 0, /* Default language */
  260. lpszMsgBuf,
  261. dwMsgBufBytes,
  262. NULL);
  263. return lpszMsgBuf;
  264. }
  265. static void rpc_error_clear(rpc_invoke_error *err)
  266. {
  267. err->err_type = RPC_NO_ERROR;
  268. err->err_code = 0;
  269. *err->err_source = 0;
  270. *err->err_detail = 0;
  271. }
  272. // [RESM(4)|总消息字节(4)|err_type(2)|err_code(2)|err_source_size(2)|err_source_string|err_detail_size(2)|err_detail_string]
  273. static BOOL rpc_error_short_msg(SOCKET s, char *buf, int size, rpc_invoke_error *err)
  274. {
  275. int pos = 0;
  276. word_t w;
  277. ushort err_source_size = (ushort)strlen(err->err_source)+1;
  278. ushort err_detail_size = (ushort)strlen(err->err_detail)+1;
  279. ulong  msglen = 4+4+2+2+2+err_source_size+2+err_detail_size;
  280. *buf = 0;
  281. assert((ulong)size>=msglen);
  282. buf[pos++] = 'R';
  283. buf[pos++] = 'E';
  284. buf[pos++] = 'S';
  285. buf[pos++] = 'M';
  286. msglen = dword_hton(msglen);
  287. memcpy(buf+pos, &msglen, 4);
  288. pos += 4;
  289. w = word_hton((word_t)err->err_type);
  290. memcpy(buf+pos, &w, 2);
  291. pos += 2;
  292. w = word_hton((word_t)err->err_code);
  293. memcpy(buf+pos, &w, 2);
  294. pos += 2;
  295. w = word_hton((word_t)err_source_size);
  296. memcpy(buf+pos, &w, 2);
  297. pos += 2;
  298. memcpy(buf+pos, err->err_source, err_source_size);
  299. pos += err_source_size;
  300. w = word_hton((word_t)err_detail_size);
  301. memcpy(buf+pos, &w, 2);
  302. pos += 2;
  303. memcpy(buf+pos, err->err_detail, err_detail_size);
  304. pos += err_detail_size;
  305. assert((ulong)pos == dword_ntoh(msglen));
  306. if (pos == (ulong)sendmsg(s, buf, pos, 0))
  307. return TRUE;
  308. err->err_type = RPC_SOCKET_ERROR;
  309. err->err_code = WSAGetLastError();
  310. *err->err_source = 0;
  311. errmsg(err->err_code, err->err_detail, RPC_ERROR_STRING_LEN);
  312. return FALSE;
  313. }
  314. static void debug_out(const char *debug_file, const char *fmt, ...)
  315. {
  316. #ifdef _DEBUG
  317. FILE *fp = 0;
  318. va_list ap;
  319. fopen_s(&fp, debug_file, "a+");
  320. assert(fp);
  321. va_start(ap, fmt);
  322. vfprintf(fp, fmt, ap);
  323. va_end(ap);
  324. fclose(fp);
  325. #endif
  326. }
  327. /*============================================================================
  328. RPC PUBLIC FUNCTIONS
  329. ============================================================================*/
  330. /**
  331. * rpc_throw_error
  332. */
  333. RPCRESULT rpc_throw_error(RPC_ERROR_TYPE err_type, LONG err_code, const char* err_source, rpc_invoke_error *err);
  334. /**
  335. * rpc_invoke_free
  336. *   创建RPC调用描述符
  337. */
  338. rpc_invoke_descriptor* rpc_invoke_create(rpc_invoke_descriptor **inv, ushort ordinal, ushort num_params);
  339. /**
  340. * rpc_invoke_init
  341. *   初始化RPC调用描述符
  342. */
  343. rpc_invoke_descriptor *
  344. rpc_invoke_init(rpc_invoke_descriptor *inv, ushort ordinal, ushort num_params);
  345. /**
  346. * rpc_invoke_clear_all
  347. *   清除RPC调用描述符, 此后RPC调用描述符可以重新绑定变量
  348. */
  349. void rpc_invoke_clear_all(rpc_invoke_descriptor *inv);
  350. /**
  351. * rpc_invoke_free
  352. *   删除RPC调用描述符, 此后RPC调用描述符将不可用
  353. */
  354. void rpc_invoke_free(rpc_invoke_descriptor *inv);
  355. /**
  356. * rpc_invoke_set_param
  357. *   设置指定的参数, 返回参数指针
  358. */
  359. rpc_param_descriptor* rpc_invoke_set_param(rpc_invoke_descriptor *inv, ushort id, word_t type);
  360. /**
  361. * rpc_param_clear
  362. *   清除参数内容
  363. */
  364. void rpc_param_clear(rpc_param_descriptor *param);
  365. /**
  366. * rpc_param_free_list
  367. *   清除参数列表内容
  368. */
  369. void rpc_param_free_list(rpc_param_descriptor *param_list, word_t num_params);
  370. /**
  371. * rpc_connection_create
  372. *   创建RPC连接
  373. */
  374. RPCRESULT rpc_connection_create(rpc_connection_descriptor **conn, const char *host, const char *port, long rcvtimeo, rpc_invoke_error *err);
  375. /**
  376. * rpc_connection_free
  377. *   清除RPC连接
  378. */
  379. void rpc_connection_free(rpc_connection_descriptor *conn);
  380. /**
  381. * rpc_connection_set
  382. *   设置RPC连接的属性
  383. */
  384. void rpc_connection_set(rpc_connection_descriptor *conn, dword_t token, dword_t timeout, byte encheader, byte encpackage);
  385. /**
  386. * rpc_connection_free
  387. *   设置输入的参数, 返回参数指针
  388. */
  389. rpc_param_descriptor* rpc_invoke_bind_param(rpc_invoke_descriptor *inv, ushort id, word_t type, void *vaddr, size_t array_size, BOOL is_owner);
  390. /**
  391. * rpc_connection_free
  392. *   计算参数字节总数
  393. */
  394. dword_t rpc_param_get_size(rpc_param_descriptor *param);
  395. /**
  396. * rpc_connection_free
  397. *   计算调用消息的字节总数
  398. */
  399. dword_t rpc_invoke_get_size(rpc_invoke_descriptor *inv);
  400. /**
  401. * rpc_invoke_marshal
  402. *   列集全部数据到totalBuf中
  403. */
  404. int rpc_invoke_marshal(rpc_invoke_descriptor *inv, char *totalBuf, int totalSize);
  405. /**
  406. * rpc_invokehdr_unmarshal
  407. *   散集调用头
  408. */
  409. RPCRESULT rpc_invokehdr_unmarshal(SOCKET sClient, dword_t dwToken, char *rpcHdr, int hdrSize, rpc_invoke_descriptor *inv, rpc_invoke_error *err);
  410. /**
  411. * rpc_invoke_unmarshal
  412. *   散集数据到参数中
  413. */
  414. RPCRESULT rpc_invoke_unmarshal(rpc_invoke_descriptor *inv,
  415. char                  *totalBuf,
  416. size_t                 totalSize,
  417. rpc_param_descriptor **out_params,
  418. word_t                *num_params,
  419. rpc_invoke_error      *err);
  420. /**
  421. * rpc_param_get_short
  422. *   取得短整数参数值
  423. */
  424. void rpc_param_get_short (rpc_param_descriptor *param, SHORT *val);
  425. /**
  426. * rpc_param_get_ushort
  427. *   取得短整数参数值
  428. */
  429. void rpc_param_get_ushort (rpc_param_descriptor *param, USHORT *val);
  430. /**
  431. * rpc_param_get_long
  432. *   取得整数参数值
  433. */
  434. void rpc_param_get_long (rpc_param_descriptor *param, LONG *val);
  435. /**
  436. * rpc_param_get_ulong
  437. *   取得无符号整数参数值
  438. */
  439. void rpc_param_get_ulong (rpc_param_descriptor *param, ULONG *val);
  440. /**
  441. * rpc_param_get_int
  442. *   取得整数参数值
  443. */
  444. void rpc_param_get_int (rpc_param_descriptor *param, INT *val);
  445. /**
  446. * rpc_param_get_double
  447. *   取得双精度参数值
  448. */
  449. void rpc_param_get_double (rpc_param_descriptor *param, double *val);
  450. /**
  451. * rpc_invoke_send
  452. *   发送数据
  453. */
  454. RPCRESULT rpc_invoke_send(rpc_connection_descriptor *conn, rpc_invoke_descriptor *inv, rpc_invoke_error *err);
  455. /**
  456. * rpc_invoke_recv
  457. *   接收数据
  458. */
  459. RPCRESULT rpc_invoke_recv(rpc_connection_descriptor *conn, rpc_invoke_descriptor *outv, rpc_invoke_error *err);
  460. /**
  461. * rpc_connection_free
  462. *   执行RPC调用
  463. */
  464. RPCRESULT rpc_invoke_execute(rpc_connection_descriptor *conn,
  465. rpc_invoke_descriptor     *inv,
  466. rpc_invoke_descriptor     *outv,
  467. rpc_invoke_error          *err);
  468. #ifdef __cplusplus
  469. }
  470. #endif
  471. #endif /* _RPCAPI_H__ */

/**
* rpcapi.h -cheungmine@gmail.com
* all rights reserved 2009
*/
#ifndef _RPCAPI_H__
#define _RPCAPI_H__
#include <winsock2.h>
#pragma comment(lib, "ws2_32.lib")
#include <process.h> /* _beginthreadex, _endthread */
#include "../rc4/unistd.h"
#include "../rc4/md5.h"
#include "../rc4/rc4.h"
#include "rpctype.h"
#include "rpcerr.h"
#ifdef __cplusplus
extern "C" {
#endif
static BOOL _rpc_is_bigendian = (('4321'>>24)=='1');
#define PARAMVALUE(pl,i,type) ((type)(*((type*) pl[i].param_bytes)))
typedef enum
{
RPC_ENCHEADER_BIT = 0,
RPC_ENCPACKAGE_BIT = 1,
RPC_BIGENDIAN_BIT = 7
}RPC_BITFLAG_ENUM;
/**
* param descriptor
*/
#define RPC_PARAM_HEADER_SIZE 16
typedef struct _rpc_param_descriptor
{
word_t param_type; // 参数类型:变量类型或结构类型
word_t size_type; // 参数类型尺寸字节
size_t array_size; // 数组元素数目: 0 不是数组; >0数组

size_t param_size; // 参数数据字节数=参数类型尺寸字节*元素数目
void *param_bytes; // 指向参数数据的指针的引用, 不复制数据
BOOL is_owner; // 是否拥有数据. 如果为TRUE, 需要free(param_bytes)
}rpc_param_descriptor;
/**
* invoke descriptor
*/
#define RPC_INVOKE_HEADER_SIZE 24 /* 不可以更改 */
typedef struct _rpc_invoke_descriptor
{
/* 24字节头 + 内容
* ['RCmn'(4)|用户标识(4)|总消息字节(4)|标志(2)| 保留(2)|原始字节数(4)|方法序号(2)|参数数目(2)]
*/
dword_t totalBytes; // 总消息字节4
word_t bitsFlag; // 标志位2: [7=BigEndian]
word_t reserved; // 保留2
dword_t result; // 返回值
// 内部值, 调用时,需要列集在bitsFlag中
dword_t invToken;
byte bigEndian;
byte encHdr;
byte encPkg;
// 如果压缩或加密, 从以下位置内容开始
ushort ordinal; // 方法序号2
ushort num_params; // 参数数目
rpc_param_descriptor *params_list; // 参数列表
// 做为输入时, 存放临时值
//
char *pbBuf;
union{
char bVal;
long lVal;
short sVal;
float fVal;
double dVal;
__int64 llVal;
};
}rpc_invoke_descriptor;
/**
* connection descriptor
*/
typedef struct _rpc_connection_descriptor
{
BOOL is_bigendian; // 字节顺序
dword_t token; // 调用标识
dword_t timeout; // 超时
byte enc_hdr; // 头加密标志
byte enc_pkg; // 参数包加密标志
SOCKET stream; // SOCKET 连接
char host[130]; // 主机名或IP地址
char port[6]; // 端口号

rpc_invoke_error last_err; // 最近的错误
char buffer[RPC_BUFFSIZE]; // 网络传输缓冲区
}rpc_connection_descriptor;
/*=============================================================================
Private Functions
host byte order and network byte order transform
=============================================================================*/
static int SafeStringSize(const char* psz)
{
return (int)(psz? (strlen(psz)+1):0);
}
/**
* More fast than swap_bytes(...) for handle word and dword type
*/
#define swap_word_type(x) ((WORD)(((((WORD)(x))&0x00ff)<<8)|((((WORD)(x))&0xff00)>>8)))
#define swap_dword_type(x) ((DWORD)(((((DWORD)(x))&0xff000000)>>24)|((((DWORD)(x))&0x00ff0000)>>8)|((((DWORD)(x))&0x0000ff00)<<8)|((((DWORD)(x))&0x000000ff)<<24)))
static void swap_bytes(void *wordP, size_t cbSize /*must be 2, 4, 8 */)
{
size_t i;
byte t;
for(i=0; i<cbSize/2; i++){
t = ((byte *) wordP)[i];
((byte *)wordP)[i] = ((byte *) wordP)[cbSize-i-1];
((byte *) wordP)[cbSize-i-1] = t;
}
}
static dword_t dword_hton(dword_t host)
{
if (!_rpc_is_bigendian)
host = swap_dword_type(host);
return host;
}
static dword_t dword_ntoh(dword_t net)
{
if (!_rpc_is_bigendian)
net = swap_dword_type(net);
return net;
}
static word_t word_hton(word_t host)
{
if (!_rpc_is_bigendian)
host = swap_word_type(host);
return host;
}
static word_t word_ntoh(word_t net)
{
if (!_rpc_is_bigendian)
net = swap_word_type(net);
return net;
}
static qword_t qword_hton(qword_t host)
{
if (!_rpc_is_bigendian)
swap_bytes(&host, sizeof(qword_t));
return host;
}
static qword_t qword_ntoh(qword_t net)
{
if (!_rpc_is_bigendian)
swap_bytes(&net, sizeof(qword_t));
return net;
}
static double double_hton(double host)
{
if (!_rpc_is_bigendian)
swap_bytes(&host, sizeof(qword_t));
return host;
}
static double double_ntoh(double net)
{
if (!_rpc_is_bigendian)
swap_bytes(&net, sizeof(qword_t));
return net;
}
static float float_hton(float host)
{
if (!_rpc_is_bigendian)
swap_bytes(&host, sizeof(dword_t));
return host;
}
static float float_ntoh(float net)
{
if (!_rpc_is_bigendian)
swap_bytes(&net, sizeof(dword_t));
return net;
}
/*=============================================================================
Private Functions
socket helper functions
=============================================================================*/
static int setbufsize(SOCKET s, int rcvlen /*RPC_BUFFSIZE*/, int sndlen /*RPC_BUFFSIZE*/)
{
int rcv, snd;
int rcvl = (int) sizeof(int);
int sndl = rcvl;
if ( getsockopt(s, SOL_SOCKET, SO_RCVBUF, (char*)&rcv, &rcvl)==SOCKET_ERROR ||
getsockopt(s, SOL_SOCKET, SO_SNDBUF, (char*)&snd, &sndl)==SOCKET_ERROR )
return SOCKET_ERROR;

if(rcv < rcvlen){
rcv = rcvlen;
rcvl = setsockopt(s, SOL_SOCKET, SO_RCVBUF, (char*)&rcv, rcvl);
assert(rcvl==0);
}

if(snd < sndlen){
snd = sndlen;
sndl = setsockopt(s, SOL_SOCKET, SO_SNDBUF, (char*)&snd, sndl);
assert(sndl==0);
}
return 0;
}
static int sendmsg(SOCKET s, const char* msgbuf, int msglen, int flags)
{
int ret;
int offset = 0;
int left = msglen;
while (left > 0) {
ret = send(s, &msgbuf[offset], left, flags);
if (ret==SOCKET_ERROR || ret==0)
return ret;
left -= ret;
offset += ret;
}
assert(offset==msglen);
return offset;
}
static int recvmsg(SOCKET s, char* msgbuf, int buflen, int flags)
{
int ret;
int offset = 0;
int left = buflen;
while (left > 0){
ret = recv(s, &msgbuf[offset], left, flags);
if (ret==SOCKET_ERROR || ret==0)
return ret;
offset += ret;
left -= ret;
}
assert(offset==buflen);
return offset;
}
static BOOL sendbulk(SOCKET s, const char* data, int dataSize, int flags, int maxmsg)
{
int send, ret;
int offset = 0;
int left = dataSize;
while (left > 0) {
send = left>maxmsg? maxmsg:left;
ret = sendmsg(s, &data[offset], send, flags);
if (ret != send)
return FALSE;
offset += ret;
left -= ret;
}
return TRUE;
}
static BOOL recvbulk(SOCKET s, char* buf, int recvlen, int flags, int maxmsg)
{
int recv, ret;
int offset = 0;
int left = recvlen;
while (left > 0){
recv = left>maxmsg? maxmsg:left;
ret = recvmsg(s, &buf[offset], recv, flags);
if (ret != recv)
return FALSE;
offset += ret;
left -= ret;
}
return TRUE;
}
static LPCSTR errmsg(DWORD dwCode, LPSTR lpszMsgBuf, DWORD dwMsgBufBytes)
{
FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, dwCode, 0, /* Default language */
lpszMsgBuf,
dwMsgBufBytes,
NULL);
return lpszMsgBuf;
}
static void rpc_error_clear(rpc_invoke_error *err)
{
err->err_type = RPC_NO_ERROR;
err->err_code = 0;
*err->err_source = 0;
*err->err_detail = 0;
}
// [RESM(4)|总消息字节(4)|err_type(2)|err_code(2)|err_source_size(2)|err_source_string|err_detail_size(2)|err_detail_string]
static BOOL rpc_error_short_msg(SOCKET s, char *buf, int size, rpc_invoke_error *err)
{
int pos = 0;
word_t w;
ushort err_source_size = (ushort)strlen(err->err_source)+1;
ushort err_detail_size = (ushort)strlen(err->err_detail)+1;
ulong msglen = 4+4+2+2+2+err_source_size+2+err_detail_size;
*buf = 0;
assert((ulong)size>=msglen);
buf[pos++] = 'R';
buf[pos++] = 'E';
buf[pos++] = 'S';
buf[pos++] = 'M';

msglen = dword_hton(msglen);
memcpy(buf+pos, &msglen, 4);
pos += 4;
w = word_hton((word_t)err->err_type);
memcpy(buf+pos, &w, 2);
pos += 2;
w = word_hton((word_t)err->err_code);
memcpy(buf+pos, &w, 2);
pos += 2;
w = word_hton((word_t)err_source_size);
memcpy(buf+pos, &w, 2);
pos += 2;
memcpy(buf+pos, err->err_source, err_source_size);
pos += err_source_size;
w = word_hton((word_t)err_detail_size);
memcpy(buf+pos, &w, 2);
pos += 2;
memcpy(buf+pos, err->err_detail, err_detail_size);
pos += err_detail_size;
assert((ulong)pos == dword_ntoh(msglen));
if (pos == (ulong)sendmsg(s, buf, pos, 0))
return TRUE;
err->err_type = RPC_SOCKET_ERROR;
err->err_code = WSAGetLastError();
*err->err_source = 0;
errmsg(err->err_code, err->err_detail, RPC_ERROR_STRING_LEN);

return FALSE;
}
static void debug_out(const char *debug_file, const char *fmt, ...)
{
#ifdef _DEBUG
FILE *fp = 0;
va_list ap;

fopen_s(&fp, debug_file, "a+");
assert(fp);

va_start(ap, fmt);
vfprintf(fp, fmt, ap);
va_end(ap);
fclose(fp);
#endif
}
/*============================================================================
RPC PUBLIC FUNCTIONS
============================================================================*/
/**
* rpc_throw_error
*/
RPCRESULT rpc_throw_error(RPC_ERROR_TYPE err_type, LONG err_code, const char* err_source, rpc_invoke_error *err);
/**
* rpc_invoke_free
* 创建RPC调用描述符
*/
rpc_invoke_descriptor* rpc_invoke_create(rpc_invoke_descriptor **inv, ushort ordinal, ushort num_params);
/**
* rpc_invoke_init
* 初始化RPC调用描述符
*/
rpc_invoke_descriptor *
rpc_invoke_init(rpc_invoke_descriptor *inv, ushort ordinal, ushort num_params);
/**
* rpc_invoke_clear_all
* 清除RPC调用描述符, 此后RPC调用描述符可以重新绑定变量
*/
void rpc_invoke_clear_all(rpc_invoke_descriptor *inv);
/**
* rpc_invoke_free
* 删除RPC调用描述符, 此后RPC调用描述符将不可用
*/
void rpc_invoke_free(rpc_invoke_descriptor *inv);
/**
* rpc_invoke_set_param
* 设置指定的参数, 返回参数指针
*/
rpc_param_descriptor* rpc_invoke_set_param(rpc_invoke_descriptor *inv, ushort id, word_t type);
/**
* rpc_param_clear
* 清除参数内容
*/
void rpc_param_clear(rpc_param_descriptor *param);
/**
* rpc_param_free_list
* 清除参数列表内容
*/
void rpc_param_free_list(rpc_param_descriptor *param_list, word_t num_params);
/**
* rpc_connection_create
* 创建RPC连接
*/
RPCRESULT rpc_connection_create(rpc_connection_descriptor **conn, const char *host, const char *port, long rcvtimeo, rpc_invoke_error *err);
/**
* rpc_connection_free
* 清除RPC连接
*/
void rpc_connection_free(rpc_connection_descriptor *conn);
/**
* rpc_connection_set
* 设置RPC连接的属性
*/
void rpc_connection_set(rpc_connection_descriptor *conn, dword_t token, dword_t timeout, byte encheader, byte encpackage);
/**
* rpc_connection_free
* 设置输入的参数, 返回参数指针
*/
rpc_param_descriptor* rpc_invoke_bind_param(rpc_invoke_descriptor *inv, ushort id, word_t type, void *vaddr, size_t array_size, BOOL is_owner);
/**
* rpc_connection_free
* 计算参数字节总数
*/
dword_t rpc_param_get_size(rpc_param_descriptor *param);
/**
* rpc_connection_free
* 计算调用消息的字节总数
*/
dword_t rpc_invoke_get_size(rpc_invoke_descriptor *inv);
/**
* rpc_invoke_marshal
* 列集全部数据到totalBuf中
*/
int rpc_invoke_marshal(rpc_invoke_descriptor *inv, char *totalBuf, int totalSize);
/**
* rpc_invokehdr_unmarshal
* 散集调用头
*/
RPCRESULT rpc_invokehdr_unmarshal(SOCKET sClient, dword_t dwToken, char *rpcHdr, int hdrSize, rpc_invoke_descriptor *inv, rpc_invoke_error *err);
/**
* rpc_invoke_unmarshal
* 散集数据到参数中
*/
RPCRESULT rpc_invoke_unmarshal(rpc_invoke_descriptor *inv,
char *totalBuf,
size_t totalSize,
rpc_param_descriptor **out_params,
word_t *num_params,
rpc_invoke_error *err);
/**
* rpc_param_get_short
* 取得短整数参数值
*/
void rpc_param_get_short (rpc_param_descriptor *param, SHORT *val);
/**
* rpc_param_get_ushort
* 取得短整数参数值
*/
void rpc_param_get_ushort (rpc_param_descriptor *param, USHORT *val);
/**
* rpc_param_get_long
* 取得整数参数值
*/
void rpc_param_get_long (rpc_param_descriptor *param, LONG *val);
/**
* rpc_param_get_ulong
* 取得无符号整数参数值
*/
void rpc_param_get_ulong (rpc_param_descriptor *param, ULONG *val);
/**
* rpc_param_get_int
* 取得整数参数值
*/
void rpc_param_get_int (rpc_param_descriptor *param, INT *val);
/**
* rpc_param_get_double
* 取得双精度参数值
*/
void rpc_param_get_double (rpc_param_descriptor *param, double *val);
/**
* rpc_invoke_send
* 发送数据
*/
RPCRESULT rpc_invoke_send(rpc_connection_descriptor *conn, rpc_invoke_descriptor *inv, rpc_invoke_error *err);
/**
* rpc_invoke_recv
* 接收数据
*/
RPCRESULT rpc_invoke_recv(rpc_connection_descriptor *conn, rpc_invoke_descriptor *outv, rpc_invoke_error *err);
/**
* rpc_connection_free
* 执行RPC调用
*/
RPCRESULT rpc_invoke_execute(rpc_connection_descriptor *conn,
rpc_invoke_descriptor *inv,
rpc_invoke_descriptor *outv,
rpc_invoke_error *err);
#ifdef __cplusplus
}
#endif
#endif /* _RPCAPI_H__ */

rpcapi.c如下:

  1. /**
  2. * rpcapi.c -cheungmine@gmail.com
  3. */
  4. #include "rpcapi.h"
  5. // 打开socket
  6. static RPCRESULT opensocket(SOCKET *pStream, const char *lpszServer, int nPort, rpc_invoke_error *pError)
  7. {
  8. struct sockaddr_in   server;
  9. struct hostent      *hp = 0;
  10. unsigned int         iAddr;
  11. *pStream = INVALID_SOCKET;
  12. // Parse server host
  13. if(inet_addr(lpszServer) == INADDR_NONE){
  14. hp = gethostbyname(lpszServer);
  15. if(hp==0)
  16. return rpc_throw_error(RPC_USER_ERROR, RPC_INVALID_HOST, "opensocket()", pError);
  17. server.sin_addr.s_addr = *((unsigned long*)hp->h_addr);
  18. }
  19. else{
  20. iAddr = inet_addr(lpszServer);
  21. server.sin_addr.s_addr = iAddr;
  22. // too slow to use gethostbyaddr
  23. //OLD:  hp = gethostbyaddr((char*)&iAddr, sizeof(iAddr), AF_INET);
  24. //OLD:  if(hp==0)
  25. //OLD:      return rpc_throw_error(RPC_USER_ERROR, RPC_INVALID_HOST, "opensocket()", pError);
  26. //OLD:  server.sin_addr.s_addr = *((unsigned long*)hp->h_addr);
  27. }
  28. server.sin_family = AF_INET;
  29. server.sin_port = htons((u_short)nPort);
  30. // Create a new socket and attempt to connect to server
  31. (*pStream) = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  32. if ((*pStream) == INVALID_SOCKET)
  33. return rpc_throw_error(RPC_SOCKET_ERROR, WSAGetLastError(), "socket()", pError);
  34. // Make a connection to the server
  35. if (connect((*pStream), (struct sockaddr *) &server, sizeof(server))==SOCKET_ERROR){
  36. closesocket( *pStream );
  37. *pStream = INVALID_SOCKET;
  38. return rpc_throw_error(RPC_SOCKET_ERROR, WSAGetLastError(), "connect()", pError);
  39. }
  40. setbufsize(*pStream, RPC_BUFFSIZE, RPC_BUFFSIZE);
  41. return RPC_SUCCESS;
  42. }
  43. // 列集参数
  44. static int rpc_param_marshal(rpc_param_descriptor *param, char *buf)
  45. {
  46. word_t   w;
  47. dword_t  dw;
  48. int pos = 0;
  49. // 参数头RPC_PARAM_HEADER_SIZE字节:
  50. //   [参数类型(2)|类型字节(2)|数组元素数目(4)|参数数据字节数(4)|参数成员数(2)=0|保留(2)=0]
  51. w = word_hton(param->param_type);
  52. memcpy(buf+pos, &w, 2);
  53. pos += 2;
  54. w = word_hton(param->size_type);
  55. memcpy(buf+pos, &w, 2);
  56. pos += 2;
  57. dw = dword_hton((dword_t)param->array_size);
  58. memcpy(buf+pos, &dw, 4);
  59. pos += 4;
  60. dw = dword_hton((dword_t)param->param_size);
  61. memcpy(buf+pos, &dw, 4);
  62. pos += 4;
  63. w = 0;
  64. memcpy(buf+pos, &w, 2);
  65. pos += 2;
  66. w = 0;
  67. memcpy(buf+pos, &w, 2);
  68. pos += 2;
  69. // 参数的数据
  70. memcpy(buf+pos, param->param_bytes, param->param_size);
  71. pos += (int)param->param_size;
  72. return pos;
  73. }
  74. // 散集参数
  75. // 参数头RPC_PARAM_HEADER_SIZE字节:
  76. //   [参数类型(2)|类型字节(2)|数组元素数目(4)|参数数据字节数(4)|参数成员数(2)|保留(2)=0]
  77. static size_t rpc_param_unmarshal(BOOL marshal_bigendian, rpc_param_descriptor *param, char *buf)
  78. {
  79. byte   *pcb;
  80. size_t  i;
  81. size_t  pos = 0;
  82. assert(param->array_size==0||param->array_size==param->param_size/param->size_type);
  83. // 参数类型
  84. param->param_type = word_ntoh(*((word_t*)(buf+pos)));
  85. pos += 2;
  86. param->size_type = word_ntoh(*((word_t*)(buf+pos)));
  87. pos += 2;
  88. param->array_size = dword_ntoh(*((dword_t*)(buf+pos)));
  89. pos += 4;
  90. param->param_size = dword_ntoh(*((dword_t*)(buf+pos)));
  91. pos += 4;
  92. // 参数成员
  93. pos += 2;
  94. // 保留值
  95. pos += 2;
  96. // 参数字节指针
  97. // 这里假设列集方marshal_bigendian和散集方_rpc_is_bigendian的字节次序一致,
  98. // 以后要添加代码处理不一致的情况
  99. if (param->param_size==0){
  100. param->param_bytes = 0;
  101. return pos;
  102. }
  103. if (param->size_type==1 || marshal_bigendian==_rpc_is_bigendian){
  104. param->param_bytes = (void*)(buf+pos);
  105. return (pos + param->param_size);
  106. }
  107. // 必须交换字节次序
  108. //
  109. assert(param->size_type==2||param->size_type==4||param->size_type==8);
  110. assert(marshal_bigendian != _rpc_is_bigendian);
  111. param->param_bytes = (void*)(buf+pos);
  112. pcb = (buf+pos);
  113. i = param->param_size/param->size_type;
  114. while(i-->0){
  115. swap_bytes(&pcb[i*param->size_type], param->size_type);
  116. }
  117. assert(i==-1);
  118. return (pos + param->param_size);
  119. }
  120. void rpc_param_get_ushort (rpc_param_descriptor *param, USHORT *val)
  121. {
  122. assert(param && param->param_bytes && param->array_size==0 &&
  123. param->param_type==RPCT_USHORT && param->size_type==RPC_TYPE_SIZE(RPCT_USHORT));
  124. *val = *((USHORT*)(param->param_bytes));
  125. }
  126. void rpc_param_get_short (rpc_param_descriptor *param, SHORT *val)
  127. {
  128. assert(param && param->param_bytes && param->array_size==0 &&
  129. param->param_type==RPCT_SHORT && param->size_type==RPC_TYPE_SIZE(RPCT_SHORT));
  130. *val = *((SHORT*)(param->param_bytes));
  131. }
  132. void rpc_param_get_long (rpc_param_descriptor *param, LONG *val)
  133. {
  134. assert(param && param->param_bytes && param->array_size==0 &&
  135. param->param_type==RPCT_LONG && param->size_type==RPC_TYPE_SIZE(RPCT_LONG));
  136. *val = *((LONG*)(param->param_bytes));
  137. }
  138. void rpc_param_get_int (rpc_param_descriptor *param, INT *val)
  139. {
  140. assert(param && param->param_bytes && param->array_size==0 &&
  141. param->param_type==RPCT_INT && param->size_type==RPC_TYPE_SIZE(RPCT_INT));
  142. *val = *((INT*)(param->param_bytes));
  143. }
  144. void rpc_param_get_ulong (rpc_param_descriptor *param, ULONG *val)
  145. {
  146. assert(param && param->param_bytes && param->array_size==0 &&
  147. param->param_type==RPCT_ULONG && param->size_type==RPC_TYPE_SIZE(RPCT_ULONG));
  148. *val = *((ULONG*)(param->param_bytes));
  149. }
  150. void rpc_param_get_double (rpc_param_descriptor *param, DOUBLE *val)
  151. {
  152. assert(param && param->param_bytes && param->array_size==0 &&
  153. param->param_type==RPCT_DOUBLE && param->size_type==RPC_TYPE_SIZE(RPCT_DOUBLE));
  154. *val = *((DOUBLE*)(param->param_bytes));
  155. }
  156. RPCRESULT rpc_invoke_send(rpc_connection_descriptor *conn, rpc_invoke_descriptor *inv, rpc_invoke_error *err)
  157. {
  158. BOOL       br;
  159. char      *buffer = 0;
  160. dword_t    cbTotal = 0;
  161. cbTotal = rpc_invoke_get_size(inv);
  162. // 既然<=RPC_BUFFSIZE, 则使用默认的buffer
  163. if (cbTotal <= RPC_BUFFSIZE){
  164. cbTotal = rpc_invoke_marshal(inv, conn->buffer, cbTotal);
  165. assert(cbTotal != -1);
  166. if (cbTotal != sendmsg(conn->stream, conn->buffer, cbTotal, 0))
  167. return rpc_throw_error(RPC_SOCKET_ERROR, WSAGetLastError(), "rpc_invoke_send()", err);
  168. else
  169. return RPC_SUCCESS;
  170. }
  171. else {
  172. buffer = malloc(cbTotal);
  173. // 内存分配失败
  174. if (!buffer)
  175. return rpc_throw_error(RPC_SYSTEM_ERROR, GetLastError(), "rpc_invoke_send()", err);
  176. cbTotal = rpc_invoke_marshal(inv, buffer, cbTotal);
  177. assert(cbTotal != -1);
  178. // 发送大块数据
  179. br = sendbulk(conn->stream, buffer, cbTotal, 0, RPC_BUFFSIZE);
  180. FREE_S(buffer)
  181. if (!br)
  182. return rpc_throw_error(RPC_SOCKET_ERROR, WSAGetLastError(), "rpc_invoke_send()", err);
  183. else
  184. return RPC_SUCCESS;
  185. }
  186. }
  187. RPCRESULT rpc_invoke_recv(rpc_connection_descriptor *conn, rpc_invoke_descriptor *outv, rpc_invoke_error *err)
  188. {
  189. RPCRESULT  res;
  190. // 接收头
  191. res = rpc_invokehdr_unmarshal(conn->stream, conn->token, conn->buffer, RPC_INVOKE_HEADER_SIZE, outv, err);
  192. if (RPC_SUCCESS != res)
  193. return res;
  194. // 验证token
  195. if (conn->token != outv->invToken)
  196. return rpc_throw_error(RPC_USER_ERROR, RPC_INVALIDMSG, "rpc_invoke_recv()", err);
  197. // 接收其余全部数据
  198. if (outv->totalBytes > RPC_BUFFSIZE){
  199. MALLOC_S(outv->pbBuf, outv->totalBytes, char);
  200. memcpy(outv->pbBuf, conn->buffer, RPC_INVOKE_HEADER_SIZE);
  201. }
  202. else{
  203. outv->pbBuf = conn->buffer;
  204. }
  205. assert(outv->pbBuf);
  206. if (!recvbulk(conn->stream, outv->pbBuf+RPC_INVOKE_HEADER_SIZE, outv->totalBytes-RPC_INVOKE_HEADER_SIZE, 0, RPC_BUFFSIZE)){
  207. if (outv->pbBuf != conn->buffer){
  208. FREE_S(outv->pbBuf)
  209. outv->pbBuf = 0;
  210. }
  211. return rpc_throw_error(RPC_USER_ERROR, RPC_NETWORK_ERROR, "rpc_invoke_recv()", err);
  212. }
  213. if (RPC_SUCCESS != rpc_invoke_unmarshal(outv, outv->pbBuf, outv->totalBytes, &outv->params_list, &outv->num_params, err)){
  214. if (outv->pbBuf != conn->buffer){
  215. FREE_S(outv->pbBuf)
  216. outv->pbBuf = 0;
  217. }
  218. return rpc_throw_error(RPC_USER_ERROR, RPC_INVALIDMSG, "rpc_invoke_recv()", err);
  219. }
  220. return RPC_SUCCESS;
  221. }
  222. /*=============================================================================
  223. Public Functions
  224. Remote Procedure Call Impementation
  225. =============================================================================*/
  226. rpc_invoke_descriptor*
  227. rpc_invoke_create(rpc_invoke_descriptor **inv, ushort ordinal, ushort num_params)
  228. {
  229. assert(inv);
  230. MALLOC_S(*inv, 1, rpc_invoke_descriptor)
  231. assert(*inv);
  232. (*inv)->bigEndian = _rpc_is_bigendian;
  233. (*inv)->ordinal = ordinal;
  234. (*inv)->num_params = num_params;
  235. MALLOC_S((*inv)->params_list, num_params, rpc_param_descriptor)
  236. return (*inv);
  237. }
  238. rpc_invoke_descriptor *
  239. rpc_invoke_init(rpc_invoke_descriptor *inv, ushort ordinal, ushort num_params)
  240. {
  241. assert(inv);
  242. rpc_invoke_clear_all(inv);
  243. inv->ordinal = ordinal;
  244. inv->num_params = num_params;
  245. MALLOC_S(inv->params_list, num_params, rpc_param_descriptor)
  246. return inv;
  247. }
  248. void rpc_invoke_clear_all(rpc_invoke_descriptor *inv)
  249. {
  250. assert(inv);
  251. if (inv->pbBuf && inv->totalBytes>RPC_BUFFSIZE){
  252. FREE_S(inv->pbBuf)
  253. assert(inv->pbBuf==0);
  254. }
  255. rpc_param_free_list(inv->params_list, inv->num_params);
  256. memset(inv, 0, sizeof(rpc_invoke_descriptor));
  257. inv->bigEndian = _rpc_is_bigendian? 1:0;
  258. }
  259. void rpc_invoke_free(rpc_invoke_descriptor *inv)
  260. {
  261. rpc_invoke_clear_all(inv);
  262. FREE_S(inv)
  263. }
  264. rpc_param_descriptor* rpc_invoke_bind_param(rpc_invoke_descriptor *inv, ushort id, word_t type, void *vaddr, size_t array_size, BOOL is_owner)
  265. {
  266. rpc_param_descriptor* p;
  267. assert(id>=0 && id<inv->num_params);
  268. p = &inv->params_list[id];
  269. p->param_type = type;
  270. p->size_type = RPC_TYPE_SIZE(type);
  271. p->array_size = array_size;
  272. p->param_bytes = vaddr;      // may be NULL
  273. if (type == RPCT_STRING)
  274. p->param_size = array_size;
  275. else
  276. p->param_size = p->size_type * (array_size > 0? array_size : 1);
  277. p->is_owner = is_owner;
  278. return p;
  279. }
  280. void rpc_param_clear(rpc_param_descriptor *p)
  281. {
  282. if (p->is_owner)
  283. FREE_S(p->param_bytes)
  284. memset(p, 0, sizeof(rpc_param_descriptor));
  285. }
  286. void rpc_param_free_list(rpc_param_descriptor *param_list, word_t num_params)
  287. {
  288. while(num_params-->0)
  289. rpc_param_clear(&param_list[num_params]);
  290. FREE_S(param_list)
  291. }
  292. RPCRESULT rpc_connection_create(rpc_connection_descriptor **conn, const char *host, const char *port, long rcvtimeo, rpc_invoke_error *err)
  293. {
  294. WSADATA   wsd;
  295. struct timeval tv_out;
  296. int       i;
  297. // 加载WinSock DLL
  298. if (WSAStartup(MAKEWORD(2, 2), &wsd) != 0)
  299. return rpc_throw_error(RPC_USER_ERROR, RPC_WINSOCK_NOTFOUND, "WSAStartup()", err);
  300. // 创建对象
  301. MALLOC_S(*conn, 1, rpc_connection_descriptor)
  302. // 设置字节顺序
  303. (*conn)->is_bigendian = _rpc_is_bigendian;
  304. // 设置主机名
  305. if (!host || host[0]==0)
  306. strcpy_s((*conn)->host, 128, "localhost");
  307. else if (strlen(host)<128)
  308. strcpy_s((*conn)->host, 128,  host);
  309. else {
  310. rpc_connection_free(*conn);
  311. return rpc_throw_error(RPC_USER_ERROR, RPC_HOSTNAME_TOOLONG, "rpc_connection_create()", err);
  312. }
  313. // 设置端口号:
  314. // 必须是 gde:xxxx
  315. if (!port || port[0]==0 || strlen(port)<4 || strlen(port)>5) {
  316. rpc_connection_free(*conn);
  317. return rpc_throw_error(RPC_USER_ERROR, RPC_INVALID_PORT, "rpc_connection_create()", err);
  318. }
  319. i = 0;
  320. while( port[i] != 0 ){
  321. if ( !isdigit(port[i]) ){
  322. rpc_connection_free(*conn);
  323. return rpc_throw_error(RPC_USER_ERROR, RPC_INVALID_PORT, "rpc_connection_create()", err);
  324. }
  325. i++;
  326. }
  327. i = atoi(port);
  328. if (i<0x0400 || i>0xFFFF) { // port = [1024,65535]
  329. rpc_connection_free(*conn);
  330. return rpc_throw_error(RPC_USER_ERROR, RPC_PORTNUM_OUTOF_SCOPE, "rpc_connection_create()", err);
  331. }
  332. strcpy_s((*conn)->port, 6, port);
  333. // 打开SOCKET
  334. if (RPC_SUCCESS != opensocket(&((*conn)->stream), host, i, err)){
  335. rpc_connection_free(*conn);
  336. return RPC_ERROR;
  337. }
  338. /*
  339. * set timeout for recv */
  340. if (rcvtimeo >= 0){
  341. tv_out.tv_sec  = rcvtimeo/1000;
  342. tv_out.tv_usec = (rcvtimeo%1000)*1000;
  343. i = setsockopt((*conn)->stream, SOL_SOCKET, SO_RCVTIMEO, (char*)&tv_out, sizeof(tv_out));
  344. assert(i == 0);
  345. }
  346. (*conn)->timeout = rcvtimeo;
  347. return RPC_SUCCESS;
  348. }
  349. void rpc_connection_free(rpc_connection_descriptor *conn)
  350. {
  351. if (conn){
  352. closesocket(conn->stream);
  353. WSACleanup();
  354. FREE_S(conn)
  355. }
  356. }
  357. void rpc_connection_set(rpc_connection_descriptor *conn, dword_t token, dword_t timeout, byte enc_hdr, byte enc_pkg)
  358. {
  359. conn->token = token;
  360. conn->timeout = timeout;
  361. conn->enc_hdr = enc_hdr;
  362. conn->enc_pkg = enc_pkg;
  363. }
  364. // 计算参数字节总数
  365. dword_t rpc_param_get_size(rpc_param_descriptor *param)
  366. {
  367. return RPC_PARAM_HEADER_SIZE + (dword_t)param->param_size;
  368. }
  369. // 计算调用消息的字节总数
  370. dword_t rpc_invoke_get_size(rpc_invoke_descriptor *inv)
  371. {
  372. ushort   i;
  373. dword_t  cbTotal = RPC_INVOKE_HEADER_SIZE;
  374. // 列集头24字节:
  375. //   ['RCmn'(4)|用户标识(4)|总消息字节(4)|标志(2)| 保留(2)|返回值(4)|方法序号(2)|参数数目(2)]
  376. // 计算列集参数字节
  377. for (i=0; i<inv->num_params; i++)
  378. cbTotal += rpc_param_get_size(&(inv->params_list[i]));
  379. return cbTotal;
  380. }
  381. // 把当前调用的数据全部放到totalBuf中, 返回全部字节数
  382. /*  24字节头 + 内容
  383. *  ['RCmn'(4)|用户token(4)|总消息字节(4)|标志(2)| 保留(2)|返回值(4)|方法序号(2)|参数数目(2)]
  384. */
  385. int rpc_invoke_marshal(rpc_invoke_descriptor *inv, char *totalBuf, int totalSize)
  386. {
  387. word_t   w;
  388. dword_t  dw;
  389. dword_t  pos;
  390. char     key[33];
  391. SET_BIT(inv->bitsFlag, RPC_BIGENDIAN_BIT, inv->bigEndian);
  392. SET_BIT(inv->bitsFlag, RPC_ENCHEADER_BIT, inv->encHdr==0? 0:1);
  393. SET_BIT(inv->bitsFlag, RPC_ENCPACKAGE_BIT, inv->encPkg==0? 0:1);
  394. // 列集方法头
  395. totalBuf[0] = 'R';
  396. totalBuf[1] = 'C';
  397. totalBuf[2] = inv->encPkg;
  398. totalBuf[3] = inv->encHdr;
  399. pos = 4;
  400. dw = dword_hton(inv->invToken);
  401. memcpy(totalBuf+pos, &dw, 4);
  402. pos += 4;
  403. dw = dword_hton(totalSize);
  404. memcpy(totalBuf+pos, &dw, 4);
  405. pos += 4;
  406. w = word_hton(inv->bitsFlag);
  407. memcpy(totalBuf+pos, &w, 2);
  408. pos += 2;
  409. w = 0;
  410. memcpy(totalBuf+pos, &w, 2);
  411. pos += 2;
  412. dw = dword_hton(inv->result);
  413. memcpy(totalBuf+pos, &dw, 4);
  414. pos += 4;
  415. w = word_hton(inv->ordinal);
  416. memcpy(totalBuf+pos, &w, 2);
  417. pos += 2;
  418. w = word_hton(inv->num_params);
  419. memcpy(totalBuf+pos, &w, 2);
  420. pos += 2;
  421. assert(pos==RPC_INVOKE_HEADER_SIZE);
  422. // 列集每个参数
  423. for (w=0; w<inv->num_params; w++){
  424. assert((int)pos<=totalSize);
  425. pos += rpc_param_marshal(&inv->params_list[w], totalBuf+pos);
  426. }
  427. // 加密包数据
  428. if (inv->encPkg != 0){
  429. dword_t dw = inv->encPkg;
  430. srand(dw);
  431. MD5_hash_string(totalBuf, RPC_INVOKE_HEADER_SIZE, (dw<<24)+rand(), key);
  432. RC4_encrypt_string(totalBuf+RPC_INVOKE_HEADER_SIZE, totalSize-RPC_INVOKE_HEADER_SIZE, key+8, 16);
  433. }
  434. // 加密消息头
  435. if (inv->encHdr != 0){
  436. dw = inv->encHdr;
  437. srand(dw);
  438. MD5_hash_string(totalBuf, 8, (dw<<16)+rand(), key);
  439. RC4_encrypt_string(totalBuf+4, RPC_INVOKE_HEADER_SIZE-4, key, 16);
  440. }
  441. return pos;
  442. }
  443. /**
  444. * 散集调用头
  445. */
  446. RPCRESULT rpc_invokehdr_unmarshal(SOCKET sClient, dword_t dwToken, char *rpcHdr, int hdrSize, rpc_invoke_descriptor *inv, rpc_invoke_error *err)
  447. {
  448. /**
  449. * Perform a blocking recv() call
  450. *  ['RCmn'(4)|用户标识(4)|总消息字节(4)|标志(2)| 保留(2)|返回值(4)|方法序号(2)|参数数目(2)] */
  451. assert(hdrSize == RPC_INVOKE_HEADER_SIZE);
  452. if (RPC_INVOKE_HEADER_SIZE != recvmsg(sClient, rpcHdr, RPC_INVOKE_HEADER_SIZE, 0))
  453. return rpc_throw_error(RPC_USER_ERROR, RPC_INVALIDMSG, "RecvRpcCallHeader", err);
  454. // 读调用声明 = "RPCn", n为0-255的密钥种子. 0表示不加密; !=0表示RC4加密的密钥种子
  455. if (rpcHdr[0]!='R'||rpcHdr[1]!='C')
  456. return rpc_throw_error(RPC_USER_ERROR, RPC_INVALIDMSG, "RecvRpcCallHeader", err);
  457. inv->encPkg = rpcHdr[2];
  458. inv->encHdr = rpcHdr[3];
  459. if (inv->encHdr != 0){
  460. dword_t dw;
  461. char    hdr[41];
  462. hdr[0]=rpcHdr[0];
  463. hdr[1]=rpcHdr[1];
  464. hdr[2]=rpcHdr[2];
  465. hdr[3]=rpcHdr[3];
  466. dw = dword_hton(dwToken);
  467. memcpy(&hdr[4], &dw, 4);
  468. dw=inv->encHdr;
  469. srand(dw);
  470. MD5_hash_string(hdr, 8, (dw<<16)+rand(), hdr+8);
  471. RC4_encrypt_string(rpcHdr+4, RPC_INVOKE_HEADER_SIZE-4, hdr+8, 16);
  472. }
  473. inv->invToken = dword_ntoh(*((dword_t*)(rpcHdr+4)));         // 用户标识
  474. inv->totalBytes = dword_ntoh(*((dword_t*)(rpcHdr+8)));           // 总消息字节数(也许是压缩的)
  475. inv->bitsFlag = word_ntoh(*((word_t*)(rpcHdr+12)));              // 标志
  476. inv->bigEndian = GET_BIT(inv->bitsFlag, RPC_BIGENDIAN_BIT);       // 客户方列集的字节次序
  477. inv->reserved = word_ntoh(*((word_t*)(rpcHdr+14)));              // 保留值
  478. inv->result = dword_ntoh(*((dword_t*)(rpcHdr+16)));              // 返回值
  479. inv->ordinal = word_ntoh(*((word_t*)(rpcHdr+20)));               // 方法序号
  480. inv->num_params = word_ntoh(*((word_t*)(rpcHdr+22)));            // 参数数目
  481. return RPC_SUCCESS;
  482. }
  483. /* 散集数据到参数中, 数据头总是不压缩的. 参数数据总是先压缩后加密的
  484. * 24字节头 + 内容
  485. *  ['RCmn'(4)|用户标识(4)|总消息字节(4)|标志(2)| 保留(2)|返回值(4)|方法序号(2)|参数数目(2)]
  486. */
  487. RPCRESULT rpc_invoke_unmarshal(rpc_invoke_descriptor *inv,
  488. char *totalBuf,
  489. size_t totalSize,
  490. rpc_param_descriptor **out_params,
  491. word_t *num_params,
  492. rpc_invoke_error *err)
  493. {
  494. ushort    i;
  495. size_t    pos;
  496. rpc_param_descriptor *params_list;
  497. assert(totalSize >= RPC_INVOKE_HEADER_SIZE);
  498. // 读调用声明 = "RCmn", m,n为0-255的密钥种子. 0表示不加密; !=0表示RC4加密的密钥种子
  499. assert(totalBuf[0]=='R'&&totalBuf[1]=='C');
  500. // 解密包数据
  501. if (inv->encPkg != 0){
  502. char    key[33];
  503. dword_t dw = inv->encPkg;
  504. srand(dw);
  505. MD5_hash_string(totalBuf, RPC_INVOKE_HEADER_SIZE, (dw<<24)+rand(), key);
  506. RC4_encrypt_string(totalBuf+RPC_INVOKE_HEADER_SIZE, totalSize-RPC_INVOKE_HEADER_SIZE, key+8, 16);
  507. }
  508. pos = RPC_INVOKE_HEADER_SIZE;
  509. // 分配参数数组
  510. MALLOC_S(params_list, inv->num_params, rpc_param_descriptor)
  511. for (i=0; i<inv->num_params; i++){
  512. pos += rpc_param_unmarshal(inv->bigEndian, &params_list[i], totalBuf+pos);
  513. }
  514. *out_params = params_list;
  515. *num_params = inv->num_params;
  516. assert(pos == totalSize);
  517. return RPC_SUCCESS;
  518. }
  519. RPCRESULT rpc_invoke_execute(rpc_connection_descriptor *conn, rpc_invoke_descriptor *inv, rpc_invoke_descriptor *outv, rpc_invoke_error* err)
  520. {
  521. inv->encHdr    = conn->enc_hdr;
  522. inv->encPkg    = conn->enc_pkg;
  523. inv->invToken  = conn->token;
  524. inv->bigEndian = conn->is_bigendian? 1:0;
  525. if (RPC_SUCCESS != rpc_invoke_send(conn, inv, err)){
  526. assert(0);
  527. return err->err_code;
  528. }
  529. if (RPC_SUCCESS != rpc_invoke_recv(conn, outv, err))
  530. return err->err_code;
  531. return RPC_SUCCESS;
  532. }

/**
* rpcapi.c -cheungmine@gmail.com
*/
#include "rpcapi.h"
// 打开socket
static RPCRESULT opensocket(SOCKET *pStream, const char *lpszServer, int nPort, rpc_invoke_error *pError)
{
struct sockaddr_in server;
struct hostent *hp = 0;
unsigned int iAddr;

*pStream = INVALID_SOCKET;
// Parse server host
if(inet_addr(lpszServer) == INADDR_NONE){
hp = gethostbyname(lpszServer);
if(hp==0)
return rpc_throw_error(RPC_USER_ERROR, RPC_INVALID_HOST, "opensocket()", pError);
server.sin_addr.s_addr = *((unsigned long*)hp->h_addr);
}
else{
iAddr = inet_addr(lpszServer);
server.sin_addr.s_addr = iAddr;

// too slow to use gethostbyaddr
//OLD: hp = gethostbyaddr((char*)&iAddr, sizeof(iAddr), AF_INET);
//OLD: if(hp==0)
//OLD: return rpc_throw_error(RPC_USER_ERROR, RPC_INVALID_HOST, "opensocket()", pError);
//OLD: server.sin_addr.s_addr = *((unsigned long*)hp->h_addr);
}
server.sin_family = AF_INET;
server.sin_port = htons((u_short)nPort);
// Create a new socket and attempt to connect to server
(*pStream) = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if ((*pStream) == INVALID_SOCKET)
return rpc_throw_error(RPC_SOCKET_ERROR, WSAGetLastError(), "socket()", pError);
// Make a connection to the server
if (connect((*pStream), (struct sockaddr *) &server, sizeof(server))==SOCKET_ERROR){
closesocket( *pStream );
*pStream = INVALID_SOCKET;
return rpc_throw_error(RPC_SOCKET_ERROR, WSAGetLastError(), "connect()", pError);
}
setbufsize(*pStream, RPC_BUFFSIZE, RPC_BUFFSIZE);
return RPC_SUCCESS;
}
// 列集参数
static int rpc_param_marshal(rpc_param_descriptor *param, char *buf)
{
word_t w;
dword_t dw;
int pos = 0;
// 参数头RPC_PARAM_HEADER_SIZE字节:
// [参数类型(2)|类型字节(2)|数组元素数目(4)|参数数据字节数(4)|参数成员数(2)=0|保留(2)=0]
w = word_hton(param->param_type);
memcpy(buf+pos, &w, 2);
pos += 2;
w = word_hton(param->size_type);
memcpy(buf+pos, &w, 2);
pos += 2;

dw = dword_hton((dword_t)param->array_size);
memcpy(buf+pos, &dw, 4);
pos += 4;
dw = dword_hton((dword_t)param->param_size);
memcpy(buf+pos, &dw, 4);
pos += 4;
w = 0;
memcpy(buf+pos, &w, 2);
pos += 2;
w = 0;
memcpy(buf+pos, &w, 2);
pos += 2;
// 参数的数据
memcpy(buf+pos, param->param_bytes, param->param_size);
pos += (int)param->param_size;
return pos;
}
// 散集参数
// 参数头RPC_PARAM_HEADER_SIZE字节:
// [参数类型(2)|类型字节(2)|数组元素数目(4)|参数数据字节数(4)|参数成员数(2)|保留(2)=0]
static size_t rpc_param_unmarshal(BOOL marshal_bigendian, rpc_param_descriptor *param, char *buf)
{
byte *pcb;
size_t i;
size_t pos = 0;
assert(param->array_size==0||param->array_size==param->param_size/param->size_type);
// 参数类型
param->param_type = word_ntoh(*((word_t*)(buf+pos)));
pos += 2;
param->size_type = word_ntoh(*((word_t*)(buf+pos)));
pos += 2;
param->array_size = dword_ntoh(*((dword_t*)(buf+pos)));
pos += 4;
param->param_size = dword_ntoh(*((dword_t*)(buf+pos)));
pos += 4;
// 参数成员
pos += 2;
// 保留值
pos += 2;
// 参数字节指针
// 这里假设列集方marshal_bigendian和散集方_rpc_is_bigendian的字节次序一致,
// 以后要添加代码处理不一致的情况
if (param->param_size==0){
param->param_bytes = 0;
return pos;
}
if (param->size_type==1 || marshal_bigendian==_rpc_is_bigendian){
param->param_bytes = (void*)(buf+pos);
return (pos + param->param_size);
}

// 必须交换字节次序
//
assert(param->size_type==2||param->size_type==4||param->size_type==8);
assert(marshal_bigendian != _rpc_is_bigendian);
param->param_bytes = (void*)(buf+pos);
pcb = (buf+pos);

i = param->param_size/param->size_type;
while(i-->0){
swap_bytes(&pcb[i*param->size_type], param->size_type);
}
assert(i==-1);
return (pos + param->param_size);
}
void rpc_param_get_ushort (rpc_param_descriptor *param, USHORT *val)
{
assert(param && param->param_bytes && param->array_size==0 &&
param->param_type==RPCT_USHORT && param->size_type==RPC_TYPE_SIZE(RPCT_USHORT));

*val = *((USHORT*)(param->param_bytes));
}
void rpc_param_get_short (rpc_param_descriptor *param, SHORT *val)
{
assert(param && param->param_bytes && param->array_size==0 &&
param->param_type==RPCT_SHORT && param->size_type==RPC_TYPE_SIZE(RPCT_SHORT));

*val = *((SHORT*)(param->param_bytes));
}
void rpc_param_get_long (rpc_param_descriptor *param, LONG *val)
{
assert(param && param->param_bytes && param->array_size==0 &&
param->param_type==RPCT_LONG && param->size_type==RPC_TYPE_SIZE(RPCT_LONG));

*val = *((LONG*)(param->param_bytes));
}
void rpc_param_get_int (rpc_param_descriptor *param, INT *val)
{
assert(param && param->param_bytes && param->array_size==0 &&
param->param_type==RPCT_INT && param->size_type==RPC_TYPE_SIZE(RPCT_INT));

*val = *((INT*)(param->param_bytes));
}
void rpc_param_get_ulong (rpc_param_descriptor *param, ULONG *val)
{
assert(param && param->param_bytes && param->array_size==0 &&
param->param_type==RPCT_ULONG && param->size_type==RPC_TYPE_SIZE(RPCT_ULONG));

*val = *((ULONG*)(param->param_bytes));
}
void rpc_param_get_double (rpc_param_descriptor *param, DOUBLE *val)
{
assert(param && param->param_bytes && param->array_size==0 &&
param->param_type==RPCT_DOUBLE && param->size_type==RPC_TYPE_SIZE(RPCT_DOUBLE));

*val = *((DOUBLE*)(param->param_bytes));
}
RPCRESULT rpc_invoke_send(rpc_connection_descriptor *conn, rpc_invoke_descriptor *inv, rpc_invoke_error *err)
{
BOOL br;
char *buffer = 0;
dword_t cbTotal = 0;

cbTotal = rpc_invoke_get_size(inv);

// 既然<=RPC_BUFFSIZE, 则使用默认的buffer
if (cbTotal <= RPC_BUFFSIZE){
cbTotal = rpc_invoke_marshal(inv, conn->buffer, cbTotal);
assert(cbTotal != -1);

if (cbTotal != sendmsg(conn->stream, conn->buffer, cbTotal, 0))
return rpc_throw_error(RPC_SOCKET_ERROR, WSAGetLastError(), "rpc_invoke_send()", err);
else
return RPC_SUCCESS;
}
else {
buffer = malloc(cbTotal);

// 内存分配失败
if (!buffer)
return rpc_throw_error(RPC_SYSTEM_ERROR, GetLastError(), "rpc_invoke_send()", err);

cbTotal = rpc_invoke_marshal(inv, buffer, cbTotal);
assert(cbTotal != -1);

// 发送大块数据
br = sendbulk(conn->stream, buffer, cbTotal, 0, RPC_BUFFSIZE);
FREE_S(buffer)
if (!br)
return rpc_throw_error(RPC_SOCKET_ERROR, WSAGetLastError(), "rpc_invoke_send()", err);
else
return RPC_SUCCESS;
}
}
RPCRESULT rpc_invoke_recv(rpc_connection_descriptor *conn, rpc_invoke_descriptor *outv, rpc_invoke_error *err)
{
RPCRESULT res;
// 接收头
res = rpc_invokehdr_unmarshal(conn->stream, conn->token, conn->buffer, RPC_INVOKE_HEADER_SIZE, outv, err);
if (RPC_SUCCESS != res)
return res;
// 验证token
if (conn->token != outv->invToken)
return rpc_throw_error(RPC_USER_ERROR, RPC_INVALIDMSG, "rpc_invoke_recv()", err);
// 接收其余全部数据
if (outv->totalBytes > RPC_BUFFSIZE){
MALLOC_S(outv->pbBuf, outv->totalBytes, char);
memcpy(outv->pbBuf, conn->buffer, RPC_INVOKE_HEADER_SIZE);
}
else{
outv->pbBuf = conn->buffer;
}
assert(outv->pbBuf);
if (!recvbulk(conn->stream, outv->pbBuf+RPC_INVOKE_HEADER_SIZE, outv->totalBytes-RPC_INVOKE_HEADER_SIZE, 0, RPC_BUFFSIZE)){
if (outv->pbBuf != conn->buffer){
FREE_S(outv->pbBuf)
outv->pbBuf = 0;
}
return rpc_throw_error(RPC_USER_ERROR, RPC_NETWORK_ERROR, "rpc_invoke_recv()", err);
}
if (RPC_SUCCESS != rpc_invoke_unmarshal(outv, outv->pbBuf, outv->totalBytes, &outv->params_list, &outv->num_params, err)){
if (outv->pbBuf != conn->buffer){
FREE_S(outv->pbBuf)
outv->pbBuf = 0;
}
return rpc_throw_error(RPC_USER_ERROR, RPC_INVALIDMSG, "rpc_invoke_recv()", err);
}
return RPC_SUCCESS;
}
/*=============================================================================
Public Functions
Remote Procedure Call Impementation
=============================================================================*/
rpc_invoke_descriptor*
rpc_invoke_create(rpc_invoke_descriptor **inv, ushort ordinal, ushort num_params)
{
assert(inv);
MALLOC_S(*inv, 1, rpc_invoke_descriptor)
assert(*inv);

(*inv)->bigEndian = _rpc_is_bigendian;
(*inv)->ordinal = ordinal;
(*inv)->num_params = num_params;

MALLOC_S((*inv)->params_list, num_params, rpc_param_descriptor)

return (*inv);
}
rpc_invoke_descriptor *
rpc_invoke_init(rpc_invoke_descriptor *inv, ushort ordinal, ushort num_params)
{
assert(inv);
rpc_invoke_clear_all(inv);
inv->ordinal = ordinal;
inv->num_params = num_params;
MALLOC_S(inv->params_list, num_params, rpc_param_descriptor)
return inv;
}
void rpc_invoke_clear_all(rpc_invoke_descriptor *inv)
{
assert(inv);
if (inv->pbBuf && inv->totalBytes>RPC_BUFFSIZE){
FREE_S(inv->pbBuf)
assert(inv->pbBuf==0);
}
rpc_param_free_list(inv->params_list, inv->num_params);
memset(inv, 0, sizeof(rpc_invoke_descriptor));
inv->bigEndian = _rpc_is_bigendian? 1:0;
}
void rpc_invoke_free(rpc_invoke_descriptor *inv)
{
rpc_invoke_clear_all(inv);
FREE_S(inv)
}
rpc_param_descriptor* rpc_invoke_bind_param(rpc_invoke_descriptor *inv, ushort id, word_t type, void *vaddr, size_t array_size, BOOL is_owner)
{
rpc_param_descriptor* p;
assert(id>=0 && id<inv->num_params);
p = &inv->params_list[id];
p->param_type = type;
p->size_type = RPC_TYPE_SIZE(type);
p->array_size = array_size;
p->param_bytes = vaddr; // may be NULL
if (type == RPCT_STRING)
p->param_size = array_size;
else
p->param_size = p->size_type * (array_size > 0? array_size : 1);

p->is_owner = is_owner;
return p;
}
void rpc_param_clear(rpc_param_descriptor *p)
{
if (p->is_owner)
FREE_S(p->param_bytes)

memset(p, 0, sizeof(rpc_param_descriptor));
}
void rpc_param_free_list(rpc_param_descriptor *param_list, word_t num_params)
{
while(num_params-->0)
rpc_param_clear(&param_list[num_params]);
FREE_S(param_list)
}
RPCRESULT rpc_connection_create(rpc_connection_descriptor **conn, const char *host, const char *port, long rcvtimeo, rpc_invoke_error *err)
{
WSADATA wsd;
struct timeval tv_out;
int i;
// 加载WinSock DLL
if (WSAStartup(MAKEWORD(2, 2), &wsd) != 0)
return rpc_throw_error(RPC_USER_ERROR, RPC_WINSOCK_NOTFOUND, "WSAStartup()", err);
// 创建对象
MALLOC_S(*conn, 1, rpc_connection_descriptor)

// 设置字节顺序
(*conn)->is_bigendian = _rpc_is_bigendian;
// 设置主机名
if (!host || host[0]==0)
strcpy_s((*conn)->host, 128, "localhost");
else if (strlen(host)<128)
strcpy_s((*conn)->host, 128, host);
else {
rpc_connection_free(*conn);
return rpc_throw_error(RPC_USER_ERROR, RPC_HOSTNAME_TOOLONG, "rpc_connection_create()", err);
}

// 设置端口号:
// 必须是 gde:xxxx
if (!port || port[0]==0 || strlen(port)<4 || strlen(port)>5) {
rpc_connection_free(*conn);
return rpc_throw_error(RPC_USER_ERROR, RPC_INVALID_PORT, "rpc_connection_create()", err);
}
i = 0;
while( port[i] != 0 ){
if ( !isdigit(port[i]) ){
rpc_connection_free(*conn);
return rpc_throw_error(RPC_USER_ERROR, RPC_INVALID_PORT, "rpc_connection_create()", err);
}
i++;
}
i = atoi(port);
if (i<0x0400 || i>0xFFFF) { // port = [1024,65535]
rpc_connection_free(*conn);
return rpc_throw_error(RPC_USER_ERROR, RPC_PORTNUM_OUTOF_SCOPE, "rpc_connection_create()", err);
}
strcpy_s((*conn)->port, 6, port);

// 打开SOCKET
if (RPC_SUCCESS != opensocket(&((*conn)->stream), host, i, err)){
rpc_connection_free(*conn);
return RPC_ERROR;
}
/*
* set timeout for recv */
if (rcvtimeo >= 0){
tv_out.tv_sec = rcvtimeo/1000;
tv_out.tv_usec = (rcvtimeo%1000)*1000;
i = setsockopt((*conn)->stream, SOL_SOCKET, SO_RCVTIMEO, (char*)&tv_out, sizeof(tv_out));
assert(i == 0);
}
(*conn)->timeout = rcvtimeo;
return RPC_SUCCESS;
}
void rpc_connection_free(rpc_connection_descriptor *conn)
{
if (conn){
closesocket(conn->stream);
WSACleanup();
FREE_S(conn)
}
}
void rpc_connection_set(rpc_connection_descriptor *conn, dword_t token, dword_t timeout, byte enc_hdr, byte enc_pkg)
{
conn->token = token;
conn->timeout = timeout;
conn->enc_hdr = enc_hdr;
conn->enc_pkg = enc_pkg;
}
// 计算参数字节总数
dword_t rpc_param_get_size(rpc_param_descriptor *param)
{
return RPC_PARAM_HEADER_SIZE + (dword_t)param->param_size;
}
// 计算调用消息的字节总数
dword_t rpc_invoke_get_size(rpc_invoke_descriptor *inv)
{
ushort i;
dword_t cbTotal = RPC_INVOKE_HEADER_SIZE;

// 列集头24字节:
// ['RCmn'(4)|用户标识(4)|总消息字节(4)|标志(2)| 保留(2)|返回值(4)|方法序号(2)|参数数目(2)]
// 计算列集参数字节
for (i=0; i<inv->num_params; i++)
cbTotal += rpc_param_get_size(&(inv->params_list[i]));

return cbTotal;
}
// 把当前调用的数据全部放到totalBuf中, 返回全部字节数
/* 24字节头 + 内容
* ['RCmn'(4)|用户token(4)|总消息字节(4)|标志(2)| 保留(2)|返回值(4)|方法序号(2)|参数数目(2)]
*/
int rpc_invoke_marshal(rpc_invoke_descriptor *inv, char *totalBuf, int totalSize)
{
word_t w;
dword_t dw;
dword_t pos;
char key[33];
SET_BIT(inv->bitsFlag, RPC_BIGENDIAN_BIT, inv->bigEndian);
SET_BIT(inv->bitsFlag, RPC_ENCHEADER_BIT, inv->encHdr==0? 0:1);
SET_BIT(inv->bitsFlag, RPC_ENCPACKAGE_BIT, inv->encPkg==0? 0:1);
// 列集方法头
totalBuf[0] = 'R';
totalBuf[1] = 'C';
totalBuf[2] = inv->encPkg;
totalBuf[3] = inv->encHdr;
pos = 4;
dw = dword_hton(inv->invToken);
memcpy(totalBuf+pos, &dw, 4);
pos += 4;
dw = dword_hton(totalSize);
memcpy(totalBuf+pos, &dw, 4);
pos += 4;

w = word_hton(inv->bitsFlag);
memcpy(totalBuf+pos, &w, 2);
pos += 2;
w = 0;
memcpy(totalBuf+pos, &w, 2);
pos += 2;
dw = dword_hton(inv->result);
memcpy(totalBuf+pos, &dw, 4);
pos += 4;
w = word_hton(inv->ordinal);
memcpy(totalBuf+pos, &w, 2);
pos += 2;
w = word_hton(inv->num_params);
memcpy(totalBuf+pos, &w, 2);
pos += 2;
assert(pos==RPC_INVOKE_HEADER_SIZE);

// 列集每个参数
for (w=0; w<inv->num_params; w++){
assert((int)pos<=totalSize);
pos += rpc_param_marshal(&inv->params_list[w], totalBuf+pos);
}
// 加密包数据
if (inv->encPkg != 0){
dword_t dw = inv->encPkg;
srand(dw);
MD5_hash_string(totalBuf, RPC_INVOKE_HEADER_SIZE, (dw<<24)+rand(), key);
RC4_encrypt_string(totalBuf+RPC_INVOKE_HEADER_SIZE, totalSize-RPC_INVOKE_HEADER_SIZE, key+8, 16);
}
// 加密消息头
if (inv->encHdr != 0){
dw = inv->encHdr;
srand(dw);
MD5_hash_string(totalBuf, 8, (dw<<16)+rand(), key);
RC4_encrypt_string(totalBuf+4, RPC_INVOKE_HEADER_SIZE-4, key, 16);
}
return pos;
}
/**
* 散集调用头
*/
RPCRESULT rpc_invokehdr_unmarshal(SOCKET sClient, dword_t dwToken, char *rpcHdr, int hdrSize, rpc_invoke_descriptor *inv, rpc_invoke_error *err)
{
/**
* Perform a blocking recv() call
* ['RCmn'(4)|用户标识(4)|总消息字节(4)|标志(2)| 保留(2)|返回值(4)|方法序号(2)|参数数目(2)] */
assert(hdrSize == RPC_INVOKE_HEADER_SIZE);
if (RPC_INVOKE_HEADER_SIZE != recvmsg(sClient, rpcHdr, RPC_INVOKE_HEADER_SIZE, 0))
return rpc_throw_error(RPC_USER_ERROR, RPC_INVALIDMSG, "RecvRpcCallHeader", err);

// 读调用声明 = "RPCn", n为0-255的密钥种子. 0表示不加密; !=0表示RC4加密的密钥种子
if (rpcHdr[0]!='R'||rpcHdr[1]!='C')
return rpc_throw_error(RPC_USER_ERROR, RPC_INVALIDMSG, "RecvRpcCallHeader", err);
inv->encPkg = rpcHdr[2];
inv->encHdr = rpcHdr[3];
if (inv->encHdr != 0){
dword_t dw;
char hdr[41];
hdr[0]=rpcHdr[0];
hdr[1]=rpcHdr[1];
hdr[2]=rpcHdr[2];
hdr[3]=rpcHdr[3];

dw = dword_hton(dwToken);
memcpy(&hdr[4], &dw, 4);
dw=inv->encHdr;
srand(dw);
MD5_hash_string(hdr, 8, (dw<<16)+rand(), hdr+8);
RC4_encrypt_string(rpcHdr+4, RPC_INVOKE_HEADER_SIZE-4, hdr+8, 16);
}

inv->invToken = dword_ntoh(*((dword_t*)(rpcHdr+4))); // 用户标识
inv->totalBytes = dword_ntoh(*((dword_t*)(rpcHdr+8))); // 总消息字节数(也许是压缩的)
inv->bitsFlag = word_ntoh(*((word_t*)(rpcHdr+12))); // 标志
inv->bigEndian = GET_BIT(inv->bitsFlag, RPC_BIGENDIAN_BIT); // 客户方列集的字节次序
inv->reserved = word_ntoh(*((word_t*)(rpcHdr+14))); // 保留值
inv->result = dword_ntoh(*((dword_t*)(rpcHdr+16))); // 返回值
inv->ordinal = word_ntoh(*((word_t*)(rpcHdr+20))); // 方法序号
inv->num_params = word_ntoh(*((word_t*)(rpcHdr+22))); // 参数数目

return RPC_SUCCESS;
}
/* 散集数据到参数中, 数据头总是不压缩的. 参数数据总是先压缩后加密的
* 24字节头 + 内容
* ['RCmn'(4)|用户标识(4)|总消息字节(4)|标志(2)| 保留(2)|返回值(4)|方法序号(2)|参数数目(2)]
*/
RPCRESULT rpc_invoke_unmarshal(rpc_invoke_descriptor *inv,
char *totalBuf,
size_t totalSize,
rpc_param_descriptor **out_params,
word_t *num_params,
rpc_invoke_error *err)
{
ushort i;
size_t pos;
rpc_param_descriptor *params_list;
assert(totalSize >= RPC_INVOKE_HEADER_SIZE);

// 读调用声明 = "RCmn", m,n为0-255的密钥种子. 0表示不加密; !=0表示RC4加密的密钥种子
assert(totalBuf[0]=='R'&&totalBuf[1]=='C');
// 解密包数据
if (inv->encPkg != 0){
char key[33];
dword_t dw = inv->encPkg;
srand(dw);
MD5_hash_string(totalBuf, RPC_INVOKE_HEADER_SIZE, (dw<<24)+rand(), key);
RC4_encrypt_string(totalBuf+RPC_INVOKE_HEADER_SIZE, totalSize-RPC_INVOKE_HEADER_SIZE, key+8, 16);
}

pos = RPC_INVOKE_HEADER_SIZE;
// 分配参数数组
MALLOC_S(params_list, inv->num_params, rpc_param_descriptor)
for (i=0; i<inv->num_params; i++){
pos += rpc_param_unmarshal(inv->bigEndian, &params_list[i], totalBuf+pos);
}
*out_params = params_list;
*num_params = inv->num_params;
assert(pos == totalSize);
return RPC_SUCCESS;
}
RPCRESULT rpc_invoke_execute(rpc_connection_descriptor *conn, rpc_invoke_descriptor *inv, rpc_invoke_descriptor *outv, rpc_invoke_error* err)
{
inv->encHdr = conn->enc_hdr;
inv->encPkg = conn->enc_pkg;
inv->invToken = conn->token;
inv->bigEndian = conn->is_bigendian? 1:0;
if (RPC_SUCCESS != rpc_invoke_send(conn, inv, err)){
assert(0);
return err->err_code;
}
if (RPC_SUCCESS != rpc_invoke_recv(conn, outv, err))
return err->err_code;
return RPC_SUCCESS;
}

整个工程的代码随后上传:

http://cheungmine.download.****.net/

from:http://blog.****.net/ubuntu64fan/article/details/5660975