天天看點

使用者自定義結構資料與VARIANT轉換 .

使用者自定義結構資料與VARIANT轉換

cheungmine

将使用者自定義的C結構資料存儲成VARIANT類型,需要時再将VARIANT類型轉為使用者自定義的結構資料,有十分現實的意義,既然我們不想為這樣的結構資料寫一個COM包裝類。雖然有很多方法和手段生成這樣的VARIANT,但是,多數時候可能需要一個更加簡單的,靈活的方法。我在做遠端過程調用的C接口時,忽然聯想到,既然RPC可以把任何資料以位元組的形式發送,那麼,就可以利用這個機制,把結構打包成位元組數組。而位元組資料是可以很友善地存儲在VARIANT中。

這個過程是廣為人知的,但是,真正把結構列內建位元組數組,如果不想使用某些标稱的序列化的方法,而全部自己寫,的确要費一番功夫。不是

技術有多難,是很繁瑣。我把前2年寫的代碼翻出來,簡單調用一下,就有了這篇文章。采用我的方法,C/C++程式員可以把自己定義的結構放到VARIANT、CComVariant、COleVariant等各種VARIANT中,也可以反向轉換。而VARIANT是可以很友善地在COM接口中傳遞。這樣,就多了一種在自動化COM接口中傳遞自定義結構的手段。

不多說廢話,全部内容見下面的代碼,我還會上傳整個工程。

struct2variant.cpp 如下:

///////////////////////////////////////////////////////////////////////   

// struct2variant.cpp   

// [email protected]   

// 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的所有權(不負責釋放記憶體) */  

            );  

                1,  

                RPCT_STRING,  

                (void*)inData->server,  

                strlen(inData->server)+1,  

                2,  

                (void*)inData->instance,  

                strlen(inData->instance)+1,  

                3,  

                (void*)inData->userid,  

                strlen(inData->userid)+1,  

                4,  

                RPCT_BOOL,  

                (void*) &inData->isdraw,  

                0,  /* 不是數組, 為0 */  

                5,  

                RPCT_ULONG,  

                (void*) &inData->token,  

                0,  

                6,  

                RPCT_LONG,  

                (void*) &inData->timeout,  

                7,  

                (void*) &inData->keepalive,  

                8,  

                (void*) &inData->reserved,  

                9,  

                (void*) &inData->status,  

                10,  

                (void*) &inData->capacity,  

                11,  

                (void*) &inData->counter,  

                12,  

                RPCT_SHORT,  

                (void*) &inData->numPts,  

                13,  

                RPCT_DOUBLE,    /* 簡單結構的成員類型 */  

                (void*) inData->ptArray, /* 記憶體結構=[x1,y1,x2,y2,...,xn,yn], 千萬不可寫成:(void*) &inData->ptArray */  

                inData->numPts * (sizeof(PointF)/sizeof(double)), /* double類型成員的數目=點數x2 */  

    /* 計算調用消息的位元組總數 */  

    dword_t cbOut = rpc_invoke_get_size(&inv);  

    char *outBuf = (char*) malloc(cbOut);  

    /* 列集全部資料到totalBuf中 */  

    rpc_invoke_marshal(&inv, outBuf, cbOut);  

    //////////////////////////////////////////////////////////   

    // 到此,我們已經在outBuf中儲存了結構的全部資料,    

    // 下面把資料轉換成IStream進而轉換成VARIANT   

    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);  

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

// [email protected]

// 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的所有權(不負責釋放記憶體) */

);

1,

RPCT_STRING,

(void*)inData->server,

strlen(inData->server)+1,

2,

(void*)inData->instance,

strlen(inData->instance)+1,

3,

(void*)inData->userid,

strlen(inData->userid)+1,

4,

RPCT_BOOL,

(void*) &inData->isdraw,

0, /* 不是數組, 為0 */

5,

RPCT_ULONG,

(void*) &inData->token,

0,

6,

RPCT_LONG,

(void*) &inData->timeout,

7,

(void*) &inData->keepalive,

8,

(void*) &inData->reserved,

9,

(void*) &inData->status,

10,

(void*) &inData->capacity,

11,

(void*) &inData->counter,

12,

RPCT_SHORT,

(void*) &inData->numPts,

13,

RPCT_DOUBLE, /* 簡單結構的成員類型 */

(void*) inData->ptArray, /* 記憶體結構=[x1,y1,x2,y2,...,xn,yn], 千萬不可寫成:(void*) &inData->ptArray */

inData->numPts * (sizeof(PointF)/sizeof(double)), /* double類型成員的數目=點數x2 */

/* 計算調用消息的位元組總數 */

dword_t cbOut = rpc_invoke_get_size(&inv);

char *outBuf = (char*) malloc(cbOut);

/* 列集全部資料到totalBuf中 */

rpc_invoke_marshal(&inv, outBuf, cbOut);

//////////////////////////////////////////////////////////

// 到此,我們已經在outBuf中儲存了結構的全部資料,

// 下面把資料轉換成IStream進而轉換成VARIANT

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);

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

/** 

 * rpcapi.h [email protected] 

 * 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" {  

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)  

        net = swap_dword_type(net);  

    return  net;  

static word_t   word_hton(word_t host)  

        host = swap_word_type(host);  

static word_t   word_ntoh(word_t net)  

        net = swap_word_type(net);  

static qword_t  qword_hton(qword_t host)  

        swap_bytes(&host, sizeof(qword_t));  

static qword_t  qword_ntoh(qword_t net)  

        swap_bytes(&net, sizeof(qword_t));  

static double   double_hton(double host)  

static double   double_ntoh(double net)  

static float    float_hton(float host)  

        swap_bytes(&host, sizeof(dword_t));  

static float    float_ntoh(float net)  

        swap_bytes(&net, sizeof(dword_t));  

                           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);  

            return ret;  

    assert(offset==buflen);  

static BOOL sendbulk(SOCKET s, const char* data, int dataSize, int flags, int maxmsg)  

    int send, ret;  

    int left = dataSize;  

        send = left>maxmsg? maxmsg:left;  

        ret = sendmsg(s, &data[offset], send, flags);  

        if (ret != send)  

            return FALSE;  

    return TRUE;  

static BOOL recvbulk(SOCKET s, char* buf, int recvlen, int flags, int maxmsg)  

    int  recv, ret;  

    int  offset = 0;  

    int  left = recvlen;  

        recv = left>maxmsg? maxmsg:left;  

        ret = recvmsg(s, &buf[offset], recv, flags);  

        if (ret != recv)  

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);  

    w = word_hton((word_t)err_source_size);  

    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, 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();  

    errmsg(err->err_code, err->err_detail, RPC_ERROR_STRING_LEN);  

    return FALSE;  

static void debug_out(const char *debug_file, const char *fmt, ...)  

    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);  

/*============================================================================ 

                       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調用描述符, 此後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_param_descriptor* rpc_invoke_bind_param(rpc_invoke_descriptor *inv, ushort id, word_t type, void *vaddr, size_t array_size, BOOL is_owner);  

 *   計算參數位元組總數 

dword_t rpc_param_get_size(rpc_param_descriptor *param);  

 *   計算調用消息的位元組總數 

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調用 

RPCRESULT rpc_invoke_execute(rpc_connection_descriptor *conn,   

                             rpc_invoke_descriptor     *inv,   

                             rpc_invoke_descriptor     *outv,   

                             rpc_invoke_error          *err);  

#endif /* _RPCAPI_H__ */  

/**

* rpcapi.h [email protected]

* 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" {

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)

net = swap_dword_type(net);

return net;

static word_t word_hton(word_t host)

host = swap_word_type(host);

static word_t word_ntoh(word_t net)

net = swap_word_type(net);

static qword_t qword_hton(qword_t host)

swap_bytes(&host, sizeof(qword_t));

static qword_t qword_ntoh(qword_t net)

swap_bytes(&net, sizeof(qword_t));

static double double_hton(double host)

static double double_ntoh(double net)

static float float_hton(float host)

swap_bytes(&host, sizeof(dword_t));

static float float_ntoh(float net)

swap_bytes(&net, sizeof(dword_t));

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);

assert(offset==buflen);

static BOOL sendbulk(SOCKET s, const char* data, int dataSize, int flags, int maxmsg)

int send, ret;

int left = dataSize;

send = left>maxmsg? maxmsg:left;

ret = sendmsg(s, &data[offset], send, flags);

if (ret != send)

return FALSE;

return TRUE;

static BOOL recvbulk(SOCKET s, char* buf, int recvlen, int flags, int maxmsg)

int recv, ret;

int offset = 0;

int left = recvlen;

recv = left>maxmsg? maxmsg:left;

ret = recvmsg(s, &buf[offset], recv, flags);

if (ret != recv)

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);

w = word_hton((word_t)err_source_size);

memcpy(buf+pos, err->err_source, err_source_size);

pos += err_source_size;

w = word_hton((word_t)err_detail_size);

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))

err->err_type = RPC_SOCKET_ERROR;

err->err_code = WSAGetLastError();

errmsg(err->err_code, err->err_detail, RPC_ERROR_STRING_LEN);

static void debug_out(const char *debug_file, const char *fmt, ...)

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);

/*============================================================================

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調用描述符, 此後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_param_descriptor* rpc_invoke_bind_param(rpc_invoke_descriptor *inv, ushort id, word_t type, void *vaddr, size_t array_size, BOOL is_owner);

* 計算參數位元組總數

dword_t rpc_param_get_size(rpc_param_descriptor *param);

* 計算調用消息的位元組總數

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調用

RPCRESULT rpc_invoke_execute(rpc_connection_descriptor *conn,

rpc_invoke_descriptor *inv,

rpc_invoke_descriptor *outv,

rpc_invoke_error *err);

#endif /* _RPCAPI_H__ */

rpcapi.c如下:

 * rpcapi.c [email protected] 

#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;  

    // 參數頭RPC_PARAM_HEADER_SIZE位元組:   

    //   [參數類型(2)|類型位元組(2)|數組元素數目(4)|參數資料位元組數(4)|參數成員數(2)=0|保留(2)=0]   

    w = word_hton(param->param_type);  

    w = word_hton(param->size_type);  

    dw = dword_hton((dword_t)param->array_size);  

    memcpy(buf+pos, &dw, 4);  

    dw = dword_hton((dword_t)param->param_size);  

    w = 0;  

    // 參數的資料   

    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)));  

    param->size_type = word_ntoh(*((word_t*)(buf+pos)));  

    param->array_size = dword_ntoh(*((dword_t*)(buf+pos)));  

    param->param_size = dword_ntoh(*((dword_t*)(buf+pos)));  

    // 參數成員   

    // 保留值   

    // 參數位元組指針   

    // 這裡假設列集方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)  

           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)  

           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)  

           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)  

           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)  

           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);  

        // 發送大塊資料   

        br = sendbulk(conn->stream, buffer, cbTotal, 0, RPC_BUFFSIZE);  

        FREE_S(buffer)  

        if (!br)  

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);  

        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)){  

                              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_init(rpc_invoke_descriptor *inv, ushort ordinal, ushort num_params)  

    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)  

    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)  

    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);  

        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) {  

        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]   

        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)){  

        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;  

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)  

    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);  

    dw = dword_hton(totalSize);  

    w = word_hton(inv->bitsFlag);  

    memcpy(totalBuf+pos, &w, 2);  

    dw = dword_hton(inv->result);  

    w = word_hton(inv->ordinal);  

    w = word_hton(inv->num_params);  

    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;  

        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')  

    inv->encPkg = rpcHdr[2];  

    inv->encHdr = rpcHdr[3];  

        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;  

        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)));            // 參數數目   

/* 散集資料到參數中, 資料頭總是不壓縮的. 參數資料總是先壓縮後加密的 

 * 24位元組頭 + 内容 

 *  ['RCmn'(4)|使用者辨別(4)|總消息位元組(4)|标志(2)| 保留(2)|傳回值(4)|方法序号(2)|參數數目(2)]  

                               char *totalBuf,   

                               size_t totalSize,  

                               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');  

    // 解密包資料   

        char    key[33];  

    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);     

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))  

* rpcapi.c [email protected]

#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 );

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;

// 參數頭RPC_PARAM_HEADER_SIZE位元組:

// [參數類型(2)|類型位元組(2)|數組元素數目(4)|參數資料位元組數(4)|參數成員數(2)=0|保留(2)=0]

w = word_hton(param->param_type);

w = word_hton(param->size_type);

dw = dword_hton((dword_t)param->array_size);

memcpy(buf+pos, &dw, 4);

dw = dword_hton((dword_t)param->param_size);

w = 0;

// 參數的資料

memcpy(buf+pos, param->param_bytes, param->param_size);

pos += (int)param->param_size;

return pos;

// 散集參數

// [參數類型(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)));

param->size_type = word_ntoh(*((word_t*)(buf+pos)));

param->array_size = dword_ntoh(*((dword_t*)(buf+pos)));

param->param_size = dword_ntoh(*((dword_t*)(buf+pos)));

// 參數成員

// 保留值

// 參數位元組指針

// 這裡假設列集方marshal_bigendian和散集方_rpc_is_bigendian的位元組次序一緻,

// 以後要添加代碼處理不一緻的情況

if (param->param_size==0){

param->param_bytes = 0;

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);

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);

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)

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)

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)

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)

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)

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

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);

// 發送大塊資料

br = sendbulk(conn->stream, buffer, cbTotal, 0, RPC_BUFFSIZE);

FREE_S(buffer)

if (!br)

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);

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)){

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_init(rpc_invoke_descriptor *inv, ushort ordinal, ushort num_params)

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)

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)

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;

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);

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) {

return rpc_throw_error(RPC_USER_ERROR, RPC_INVALID_PORT, "rpc_connection_create()", err);

i = 0;

while( port[i] != 0 ){

if ( !isdigit(port[i]) ){

i++;

i = atoi(port);

if (i<0x0400 || i>0xFFFF) { // port = [1024,65535]

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)){

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;

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)

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);

dw = dword_hton(totalSize);

w = word_hton(inv->bitsFlag);

memcpy(totalBuf+pos, &w, 2);

dw = dword_hton(inv->result);

w = word_hton(inv->ordinal);

w = word_hton(inv->num_params);

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;

MD5_hash_string(totalBuf, 8, (dw<<16)+rand(), key);

RC4_encrypt_string(totalBuf+4, RPC_INVOKE_HEADER_SIZE-4, key, 16);

* 散集調用頭

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')

inv->encPkg = rpcHdr[2];

inv->encHdr = rpcHdr[3];

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;

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))); // 參數數目

/* 散集資料到參數中, 資料頭總是不壓縮的. 參數資料總是先壓縮後加密的

* 24位元組頭 + 内容

* ['RCmn'(4)|使用者辨別(4)|總消息位元組(4)|标志(2)| 保留(2)|傳回值(4)|方法序号(2)|參數數目(2)]

char *totalBuf,

size_t totalSize,

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');

// 解密包資料

char key[33];

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);

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))

整個工程的代碼随後上傳:

<a href="http://cheungmine.download.csdn.net/">http://cheungmine.download.csdn.net/</a>

繼續閱讀