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

330 篇文章 4 订阅 ¥19.90 ¥99.00
201 篇文章 2 订阅 ¥19.90 ¥99.00
66 篇文章 0 订阅

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

 

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

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

 

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

struct2variant.cpp 如下:

 

view plaincopy to clipboardprint?
///  
// 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);  

///
// 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可以参考如下:

view plaincopy to clipboardprint?
/** 
 * 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.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如下:

view plaincopy to clipboardprint?
/** 
 * 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;  

/**
 * 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://download.csdn.net/source/2445024

 

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/cheungmine/archive/2010/06/10/5660975.aspx

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值