• ActiveSync应用层程序协议分析RAPI的握手过程


    ActiveSync应用层程序协议分析-RAPI的握手过程

     

    转载时请注明出处和作者联系方式
    作者联系方式:李先静 <xianjimli at hotmail dot com>

     

    ActiveSyncWindow Mobile之间的通信协议并不复杂,在RNDIS+USBNET之上运行TCP/IP,而TCP/IP之上的应用层协议包括RAPIRRAC两个协议。前段时间我完成RAPIRRAC协议的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是宽字符,而platformmodel是多字节字符串,和前面的name不统一不说,还无法知道它们的编码方式,更烂的是platformmodel前面长度的意义不一致。

     

    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;

          

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

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

                  if(ret != ASM_RET_OK) break;

                  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)

    {

           AsmRet ret = ASM_RET_FAIL;

           asm_return_val_if_fail(thiz != NULL, ret);

     

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

           RapiDeviceInfo info = {0};

           size_t length = 0;

           unsigned int cmd = 0;

           unsigned int resp = 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);

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

           assert(length == sizeof(cmd));

     

           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;

    }

     

    ~~end~~

     
  • 相关阅读:
    为什么我要用 Node.js? 案例逐一介绍
    不用 Twitter Bootstrap 的5个理由
    20个最强的基于浏览器的在线代码编辑器
    你需要了解 Windows Phone 8.1 的11件事
    你知道吗?什么是 Responsive JavaScript ?
    2014年最佳的10款 PHP 开发框架
    你知道吗?10个精妙的 Java 编码最佳实践
    知识笔记:jQuery 事件对象属性小结
    你知道吗?undefined 与 null 的区别
    Java开发者应该列入年度计划的5件事
  • 原文地址:https://www.cnblogs.com/zhangyunlin/p/6167657.html
Copyright © 2020-2023  润新知