天天看點

ActiveSync應用層程式協定分析-RAPI的握手過程

ActiveSync應用層程式協定分析-RAPI的握手過程

ActiveSync與Window Mobile之間的通信協定并不複雜,在RNDIS+USBNET之上運作TCP/IP,而TCP/IP之上的應用層協定包括RAPI和RRAC兩個協定。前段時間我完成RAPI和RRAC協定的PC端和裝置端的實作,在這個系列之中,我們将對它們的原理和實作進行分析,供要做類似工作的朋友參考。本文介紹一下RAPI的握手過程。

PC端的ActiveSync監聽990端口,同步時裝置連接配接到這個端口,然後開始握手:

1.裝置端發送四個位元組的資料(0x00)表示請求握手。

2.PC端回應四個位元組的資料(0x03)表示接受握手,并要求裝置提供裝置資訊。

3.裝置回應四個位元組的資料(0x04)表示要上傳裝置資訊,并在其後緊跟裝置資訊。

4.PC端讀取裝置資訊,如果不要求論證,握手到此結束(要求握手的情況目前還不清楚)。

裝置資訊結構如下:

       typedef struct _RapiDeviceInfo

       {

              RapiDeviceGuid   guid;

              unsigned int os_version_major;

              unsigned int os_version_minor;

              WStr*  name;

              unsigned int dev_version;

              unsigned int cpu_type;

              unsigned int dev_magic;

              unsigned int current_partner;

              unsigned int dev_id;

              char*  platform;

              char*  model;

              unsigned int components_nr;

              RapiComponent* components;

              unsigned int pw_key;

       }RapiDeviceInfo;

這個資料包前面四個位元組是這個結構的資料長度,後面的資料并不是直接按結構記憶體布局映射過來的,而是有專門編碼方式。主要特殊之外在于,所有整數都是以小端格式存放,name之前有四個位元組代表name的字元數(不包括空字元), platform之前有四個位元組代表platform的位元組數(此時包括空字元),model之前有四個位元組代表model的位元組數(此時不包括空字數)。由這個結構可以看出微軟當時把這個協定定義得太爛了:name是寬字元,而platform和model是多位元組字元串,和前面的name不統一不說,還無法知道它們的編碼方式,更爛的是platform和model前面長度的意義不一緻。

PC端的代碼類似于:

static AsmRet rapi_host_connection_device_handle_hand_shake(AsmConnection* thiz)

{

       AsmRet ret = ASM_RET_FAIL;

       asm_return_val_if_fail(thiz != NULL, ASM_RET_FAIL);

       PrivInfo* priv = (PrivInfo*)thiz->priv;

       asm_return_val_if_fail(priv->stream != NULL, ASM_RET_OK);

       int length = 0;

       unsigned int cmd = 0;

       unsigned int resp = 0;

       AsmInputBuffer* input = NULL;

       do

              ret = asm_stream_read(priv->stream, &cmd, sizeof(cmd), &length);

              if(ret != ASM_RET_OK || cmd != RAPI_COMMAND_HAND_SHAKE) break;

              resp = RAPI_RESP_HAND_SHAKE;

              ret = asm_stream_write(priv->stream, &resp, sizeof(resp), &length);

              if(ret != ASM_RET_OK) break;

              if(ret != ASM_RET_OK || cmd != RAPI_RESP_GET_INFO) break;

              input = asm_input_buffer_create(NULL, 0, ASM_ENDIAN_LITTLE, NULL);

              ret = rapi_stream_read(priv->stream, input);

              ret = rapi_host_connection_device_parse_device_info(thiz, input);

       }while(0);

       if(ret != ASM_RET_OK)

              asm_stream_destroy(priv->stream);

              priv->stream = NULL;

              printf("%s:%d hand shake failed./n", __func__, __LINE__);

       }

       asm_input_buffer_destroy(input);

       return ASM_RET_OK;

}

裝置端的代碼類似于:

static AsmRet rapi_device_connection_device_hand_shake(AsmConnection* thiz)

       asm_return_val_if_fail(thiz != NULL, ret);

       RapiDeviceInfo info = {0};

       size_t length = 0;

       asm_output_buffer_reset(priv->output);

       cmd = uint32_to_endian(RAPI_COMMAND_HAND_SHAKE, ASM_ENDIAN_LITTLE);

       ret = asm_stream_write(priv->stream, &cmd, sizeof(cmd), &length);

       assert(length == sizeof(cmd));

       ret = asm_stream_read(priv->stream, &resp, sizeof(resp), &length);

       assert(length == sizeof(resp));

       assert(resp == RAPI_RESP_HAND_SHAKE);

       cmd = uint32_to_endian(RAPI_RESP_GET_INFO, ASM_ENDIAN_LITTLE);

       if(rapi_device_get_info(priv->device, &info) == ASM_RET_OK)

              if(rapi_buffer_write_info(priv->output, &info) == ASM_RET_OK)

              {

                     ret = rapi_stream_write(priv->stream, priv->output);

              }

       return ret;