分布式软总线的编译和运行

目前聚元 PolyOS 在 硬件 Sifive Unmatched 开发板上集成了分布式软总线功能,实验所用的 OpenHarmony 设备采用的是 DAYU200 开发板。未来,聚元 PolyOS 将继续在日益丰富的 RISC-V 硬件SoC架构上适配分布式软总线功能。

下面从编译和运行分布式软总线应用说明两方面介绍其使用。

分布式软总线编译

具体见 build_portal环境搭建及使用 关于 unmatched 的编译使用。

分布式软总线应用说明

将编译出来的 demo-coreip-cli-unmatched.wic.xz,烧录到 SD 卡中。(sdX 更改为 SD 卡实际设备文件)

xzcat demo-coreip-cli-unmatched.wic.xz | sudo dd of=/dev/sdX bs=512K iflag=fullblock oflag=direct conv=fsync status=progress

将烧录完成的 SD 卡插入 Sifive Unmatched 开发板中的 MicroSD 卡槽后启动开发板。

服务端启动

服务端主程序名为 softbus_server_main 。

软总线通过独立进程部署的方式对外提供服务,通过执行服务端主程序可拉起软总线进程提供对外服务,实验时聚元 PolyOS 和 OpenHarmony 设备均需启动软总线服务,OpenHarmony 系统已默认启动,无需单独拉起软总线服务进程。

softbus_server_main >log.file &

1.当服务端被拉起时,会主动通过名为 ethX/wifiX 的网络设备进行 coap 广播,对对端设备进行自动探测。

2.当探测到对端设备且对端设备为可信设备时,还会自动组网操作,以便后后续客户端进行快速连接和传输(“添加可信设备”见下文)。

3.日志模块可通过重定向接管,有条件者还可通过实现和替换软总线依赖的 hilog 模块,进行更细致的日志管理。

4.服务端依赖于系统参数模块 syspara,以获取设备唯一的 UDID。聚元 PolyOS 预留了 /etc/SN 的文件接口,作为生成 UDID 的参数。

注意

  • SN 号可为 64 字节长度内的任意字符串。

  • 用户需保证单设备节点上有且仅有唯一的 softbus_server_main 进程。

  • 用户需在启动 softbus_server_main 前配置 /etc/SN,并保证多设备下 SN 号的唯一性。

可信设备认证

软总线在创建连接的过程中,会调用 hichain 模块的认证接口,与对端的设备进行认证操作。hichain 模块为 OpenHarmony 提供设备认证能力,支持通过点对点认证方式创建可信群组。

聚元 PolyOS 和 OpenHarmony 设备之间要互连互通,则需要在聚元 PolyOS 上支持 hichain 的点对点认证和可信群组创建能力。

hichain 模块与软总线一样,分为服务端和客户端,实验中聚元 PolyOS 和 OpenHarmony 设备均可以作为服务端或客户端:

  • 服务端:用户仅需拉起 hichain 服务端,无需额外操作服务端。

  • 客户端:通过 hichain 的客户端提供的 API,可以创建群组,并请求添加群组成员,从而将多个设备添加到可信群组。

hichain 的客户端提供动态链接库 libdeviceauth_sdk.z.so,用户可以单独链接 hichain 的客户端进行可信群组创建。

${CROSS_COMPILE}ld -ldeviceauth_sdk.z

在可信群组创建后,软总线会自动触发组网,支持后续软总线客户端的连接和传输。

hichain 的客户端 API 头文件为 device_auth.h,可在客户端代码中引用。

  1. 直接调用接口

InitDeviceAuthService

初始化hichain客户端

GetGmInstance

获取客户端群组管理的操作函数组

DestroyDeviceAuthService

注销hichain客户端

  1. GetGmInstance返回的操作函数组

regCallback

注册群组创建和请求回调函数

unRegCallback

解注册群组回调函数

createGroup

创建新的群组

getGroupInfo

查询本地群组信息

destroyInfo

释放通过getGroupInfo申请的内存

addMemberToGroup

请求添加成员到群组

isDeviceInGroup

查询某个设备是否在群组中

  1. 使用范例

按照 hichain 的点对点 pin 码认证方式,需要通过设备创建群组( host ),另一个台设备请求添加成员到该群组( target ),实例代码如下:

#include <stdio.h>
#include <string.h>
#include <cJSON.h>
#include <securec.h>
#include <discovery_service.h>
#include <session.h>
#include <device_auth.h>
#include <parameter.h>

#define APP_ID "hichain_test"
#define DEFAULT_CAPABILITY "osdCapability"
#define PUBLISH_ID 123

#define DEFAULT_GROUP_NAME "dsoftbus"
#define DEFAULT_PIN_CODE "123456"
#define MAX_UDID_LEN 65
#define MAX_GROUP_LEN 65
#define ERR_RET -1

#define FIELD_ETH_IP "ETH_IP"
#define FIELD_ETH_PORT "ETH_PORT"
#define FIELD_WLAN_IP "WIFI_IP"
#define FIELD_WLAN_PORT "WIFI_PORT"

enum {
   DEVICE_DISCOVERY = 0,
   DEVICE_JOINING,
   DEVICE_ONLINE,
}DeviceStatus;

char *g_deviceStatus[] = {
   "discovery",
   "joining",
   "online",
};

typedef struct DeviceList {
   struct DeviceList *next;
   DeviceInfo device;
   int status;
   int64_t requestId;
} DeviceList;
DeviceList *g_deviceListHead = NULL;

static const DeviceGroupManager *g_hichainGmInstance = NULL;
static char g_udid[MAX_UDID_LEN];
static char g_groupId[MAX_GROUP_LEN];
static int64_t g_requestId = 1;

static const char *GetStringFromJson(const cJSON *obj, const char *key)
{
   cJSON *item;

   if (obj == NULL || key == NULL)
      return NULL;

   item = cJSON_GetObjectItemCaseSensitive(obj, key);
   if (item != NULL && cJSON_IsString(item)) {
      return cJSON_GetStringValue(item);
   } else {
      int len = cJSON_GetArraySize(obj);
      for (int i = 0; i < len; i++) {
         item = cJSON_GetArrayItem(obj, i);
         if (cJSON_IsObject(item)) {
            const char *value = GetStringFromJson(item, key);
            if (value != NULL)
               return value;
         }
      }
   }
   return NULL;
}

static int HichainSaveGroupID(const char *param)
{
   cJSON *msg = cJSON_Parse(param);
   const char *value = NULL;

   if (msg == NULL) {
      printf("HichainSaveGroupID: cJSON_Parse fail\n");
      return ERR_RET;
   }

   value = GetStringFromJson(msg, FIELD_GROUP_ID);
   if (value == NULL) {
      printf("HichainSaveGroupID:GetStringFromJson fail\n");
      cJSON_Delete(msg);
      return ERR_RET;
   }

   memcpy_s(g_groupId, MAX_GROUP_LEN, value, strlen(value));
   printf("HichainSaveGroupID:groupID=%s\n", g_groupId);

   cJSON_Delete(msg);
   return 0;
}

static void HiChainGmOnFinish(int64_t requestId, int operationCode, const char *returnData)
{
   if (operationCode == GROUP_CREATE && returnData != NULL) {
      printf("create new group finish:requestId=%ld, returnData=%s\n", requestId, returnData);
      HichainSaveGroupID(returnData);
   } else if (operationCode == MEMBER_JOIN) {
      DeviceList *node = g_deviceListHead;

      printf("member join finish:requestId=%ld, returnData=%s\n", requestId, returnData);
      while (node) {
         if (node->requestId != requestId) {
            node = node->next;
            continue;
         }
         node->status = DEVICE_ONLINE;
         break;
      }
   } else {
      printf("<HiChainGmOnFinish>CB:requestId=%ld, operationCode=%d, returnData=%s\n", requestId, operationCode, returnData);
   }
}

static void HiChainGmOnError(int64_t requestId, int operationCode, int errorCode, const char *errorReturn)
{
   DeviceList *node = g_deviceListHead;

   printf("<HiChainGmOnError>CB:requestId=%ld, operationCode=%d, errorCode=%d, errorReturn=%s\n", requestId, operationCode, errorCode, errorReturn);
   while (node) {
      if (node->requestId != requestId) {
         node = node->next;
         continue;
      }
      node->status = DEVICE_DISCOVERY;
      break;
   }
}

static char *HiChainGmOnRuest(int64_t requestId, int operationCode, const char *reqParams)
{
   cJSON *msg = cJSON_CreateObject();
   char *param = NULL;

   printf("<HiChainGmOnRuest>CB:requestId=%ld, operationCode=%d, reqParams=%s", requestId, operationCode, reqParams);

   if (operationCode != MEMBER_JOIN) {
      return NULL;
   }

   if (msg == NULL) {
      printf("HiChainGmOnRuest: cJSON_CreateObject fail\n");
   }

   if (cJSON_AddNumberToObject(msg, FIELD_CONFIRMATION, REQUEST_ACCEPTED) == NULL ||
      cJSON_AddStringToObject(msg, FIELD_PIN_CODE, DEFAULT_PIN_CODE) == NULL ||
      cJSON_AddStringToObject(msg, FIELD_DEVICE_ID, g_udid) == NULL) {
      printf("HiChainGmOnRuest: cJSON_AddToObject fail\n");
      cJSON_Delete(msg);
      return NULL;
   }

   param = cJSON_PrintUnformatted(msg);
   cJSON_Delete(msg);
   return param;
}

static const DeviceAuthCallback g_groupManagerCallback = {
   .onRequest = HiChainGmOnRuest,
   .onError = HiChainGmOnError,
   .onFinish = HiChainGmOnFinish,
};

static int HichainGmRegCallback(void)
{
   return g_hichainGmInstance->regCallback(APP_ID, &g_groupManagerCallback);
}

static void HichainGmUnRegCallback(void)
{
   g_hichainGmInstance->unRegCallback(APP_ID);
}

static int HichainGmGetGroupInfo(char **groupVec, uint32_t *num)
{
   cJSON *msg = cJSON_CreateObject();
   char *param = NULL;
   int ret = ERR_RET;

   if (msg == NULL) {
      printf("HichainGmGetGroupInfo: cJSON_CreateObject fail\n");
      return ret;
   }

   if (cJSON_AddNumberToObject(msg, FIELD_GROUP_TYPE, PEER_TO_PEER_GROUP) == NULL ||
      cJSON_AddStringToObject(msg, FIELD_GROUP_NAME, DEFAULT_GROUP_NAME) == NULL ||
      cJSON_AddNumberToObject(msg, FIELD_GROUP_VISIBILITY, GROUP_VISIBILITY_PUBLIC) == NULL) {
      printf("HichainGmGetGroupInfo: cJSON_AddToObject fail\n");
      goto err_cJSON_Delete;
   }
   param = cJSON_PrintUnformatted(msg);
   if (param == NULL) {
      printf("HichainGmGetGroupInfo: cJSON_PrintUnformatted fail\n");
      goto err_cJSON_Delete;
   }

   ret = g_hichainGmInstance->getGroupInfo(ANY_OS_ACCOUNT, APP_ID, param, groupVec, num);
   if (ret != 0) {
      printf("getGroupInfo fail:%d", ret);
      goto err_getGroupInfo;
   }

err_getGroupInfo:
   cJSON_free(param);
err_cJSON_Delete:
   cJSON_Delete(msg);
   return ret;
}

static void HichainGmDestroyGroupInfo(char **groupVec)
{
   g_hichainGmInstance->destroyInfo(groupVec);
}

static int HichainGmCreatGroup(void)
{
   cJSON *msg = cJSON_CreateObject();
   char *param = NULL;
   int ret = ERR_RET;

   if (msg == NULL)
      return ret;

   if (cJSON_AddNumberToObject(msg, FIELD_GROUP_TYPE, PEER_TO_PEER_GROUP) == NULL ||
      cJSON_AddStringToObject(msg, FIELD_DEVICE_ID, g_udid) == NULL ||
      cJSON_AddStringToObject(msg, FIELD_GROUP_NAME, DEFAULT_GROUP_NAME) == NULL ||
      cJSON_AddNumberToObject(msg, FIELD_USER_TYPE, 0) == NULL ||
      cJSON_AddNumberToObject(msg, FIELD_GROUP_VISIBILITY, GROUP_VISIBILITY_PUBLIC) == NULL ||
      cJSON_AddNumberToObject(msg, FIELD_EXPIRE_TIME, EXPIRE_TIME_MAX) == NULL) {
      printf("HichainGmCreatGroup: cJSON_AddToObject fail\n");
      cJSON_Delete(msg);
      return ret;
   }
   param = cJSON_PrintUnformatted(msg);
   if (param == NULL) {
      printf("HichainGmCreatGroup: cJSON_PrintUnformatted fail\n");
      cJSON_Delete(msg);
      return ret;
   }

   ret = g_hichainGmInstance->createGroup(ANY_OS_ACCOUNT, g_requestId++, APP_ID, param);

   cJSON_free(param);
   cJSON_Delete(msg);
   return ret;
}

static bool HichainIsDeviceInGroup(const char *groupId, const char *devId)
{
   return g_hichainGmInstance->isDeviceInGroup(ANY_OS_ACCOUNT, APP_ID, groupId, devId);
}

static int HichainGmAddMemberToGroup(DeviceInfo *device, const char *groupId)
{
   cJSON *msg = cJSON_CreateObject();
   cJSON *addr = NULL;
   char *param = NULL;
   int ret = ERR_RET;

   if (msg == NULL) {
      printf("HichainGmAddMemberToGroup: cJSON_CreateObject1 fail\n");
      return ret;
   }

   addr = cJSON_CreateObject();
   if (addr == NULL) {
      printf("HichainGmAddMemberToGroup: cJSON_CreateObject2 fail\n");
      goto err_cJSON_CreateObject;
   }

   for (unsigned int i = 0; i < device->addrNum; i++) {
      if (device->addr[i].type == CONNECTION_ADDR_ETH) {
         if (cJSON_AddStringToObject(addr, FIELD_ETH_IP, device->addr[i].info.ip.ip) == NULL ||
               cJSON_AddNumberToObject(addr, FIELD_ETH_PORT, device->addr[i].info.ip.port) == NULL) {
            printf("HichainGmAddMemberToGroup: cJSON_AddToObject1 fail\n");
            goto err_cJSON_AddToObject;
         }
      } else if (device->addr[i].type == CONNECTION_ADDR_WLAN) {
         if (cJSON_AddStringToObject(addr, FIELD_WLAN_IP, device->addr[i].info.ip.ip) == NULL ||
               cJSON_AddNumberToObject(addr, FIELD_WLAN_PORT, device->addr[i].info.ip.port) == NULL) {
            printf("HichainGmAddMemberToGroup: cJSON_AddToObject2 fail\n");
            goto err_cJSON_AddToObject;
         }
      } else {
         printf("unsupport connection type:%d\n", device->addr[i].type);
         goto err_cJSON_AddToObject;
      }
   }

   param = cJSON_PrintUnformatted(addr);
   if (param == NULL) {
      printf("HichainGmAddMemberToGroup: cJSON_PrintUnformatted1 fail\n");
      goto err_cJSON_AddToObject;
   }

   if (cJSON_AddStringToObject(msg, FIELD_GROUP_ID, groupId) == NULL ||
      cJSON_AddNumberToObject(msg, FIELD_GROUP_TYPE, PEER_TO_PEER_GROUP) == NULL ||
      cJSON_AddStringToObject(msg, FIELD_PIN_CODE, DEFAULT_PIN_CODE) == NULL ||
      cJSON_AddStringToObject(msg, FIELD_DEVICE_ID, g_udid) == NULL ||
      cJSON_AddStringToObject(msg, FIELD_GROUP_NAME, DEFAULT_GROUP_NAME) == NULL ||
      cJSON_AddBoolToObject(msg, FIELD_IS_ADMIN, false) == NULL ||
      cJSON_AddStringToObject(msg, FIELD_CONNECT_PARAMS, param) == NULL) {
      printf("HichainGmAddMemberToGroup: cJSON_AddToObject4 fail\n");
      goto err_cJSON_AddToObject1;
   }

   cJSON_free(param);
   param = cJSON_PrintUnformatted(msg);
   if (param == NULL) {
      printf("HichainGmAddMemberToGroup: cJSON_PrintUnformatted fail\n");
      goto err_cJSON_CreateObject;
   }

   ret = g_hichainGmInstance->addMemberToGroup(ANY_OS_ACCOUNT, g_requestId++, APP_ID, param);
   if (ret != 0) {
      printf("addMemberToGroup fail:%d\n", ret);
   }

err_cJSON_AddToObject1:
   cJSON_free(param);
err_cJSON_AddToObject:
   cJSON_Delete(addr);
err_cJSON_CreateObject:
   cJSON_Delete(msg);
   return ret;
}

static int HichainInit(void)
{
   char *groupVec = NULL;
   uint32_t num;
   int ret;

   ret = InitDeviceAuthService();
   if (ret != 0) {
      printf("InitDeviceAuthService fail:%d\n", ret);
      return ret;
   }

   g_hichainGmInstance = GetGmInstance();
   if (g_hichainGmInstance == NULL) {
      printf("GetGmInstance fail\n");
      ret = ERR_RET;
      goto err_GetGmInstance;
   }

   ret = HichainGmRegCallback();
   if (ret != 0) {
      printf("HichainGmregCallback fail.:%d\n", ret);
      goto err_HichainGmRegCallback;
   }

   ret = HichainGmGetGroupInfo(&groupVec, &num);
   if (ret != 0) {
      printf("HichainGmGetGroupInfo fail:%d\n", ret);
      goto err_HichainGmGetGroupInfo;
   }

   if (num == 0) {
      ret = HichainGmCreatGroup();
      if (ret) {
         printf("HichainGmCreatGroup fail:%d\n", ret);
         goto err_HichainGmCreatGroup;
      }
   } else {
      printf("HichainGmGetGroupInfo:num=%u\n", num);
      HichainSaveGroupID(groupVec);
      HichainGmDestroyGroupInfo(&groupVec);
   }

   return 0;

err_HichainGmCreatGroup:
err_HichainGmGetGroupInfo:
   HichainGmUnRegCallback();
err_HichainGmRegCallback:
err_GetGmInstance:
   DestroyDeviceAuthService();
   return ret;
}

static void CheckDeviceStatus(void)
{
   DeviceList *node = g_deviceListHead;
   char *groupVec = NULL;
   uint32_t num;
   int ret;

   ret = HichainGmGetGroupInfo(&groupVec, &num);
   if (ret != 0 || num == 0) {
      printf("HichainGmGetGroupInfo fail\n");
      return;
   }

   ret = HichainSaveGroupID(groupVec);
   if (ret != 0)
      goto err_HichainSaveGroupID;

   while (node) {
      if (HichainIsDeviceInGroup(g_groupId, node->device.devId)) {
         node->status = DEVICE_ONLINE;
      }
      node = node->next;
   }

err_HichainSaveGroupID:
   HichainGmDestroyGroupInfo(&groupVec);
}

static bool CheckDeviceExist(const DeviceInfo *device)
{
   DeviceList *node = g_deviceListHead;

   while (node) {
      if (strcmp(device->devId, node->device.devId) == 0) {
         return true;
      }
      node = node->next;
   }
   return false;
}

static void SaveDeviceInfo(const DeviceInfo *device)
{
   DeviceList *node = malloc(sizeof(DeviceList));

   if (node == NULL) {
      printf("SaveDeviceInfo: malloc fail\n");
      return;
   }

   node->device = *device;
   node->requestId = ERR_RET;
   node->status = DEVICE_DISCOVERY;
   if (g_deviceListHead == NULL) {
      node->next = NULL;
   } else {
      node->next = g_deviceListHead;
   }
   g_deviceListHead = node;
}

static DeviceList *GetDeviceInfo(int idx)
{
   DeviceList *node = g_deviceListHead;
   while (node) {
      if (--idx == 0) {
         return node;
      }
      node = node->next;
   }
   return NULL;
}

static void FreeDeviceInfo()
{
   while (g_deviceListHead) {
      DeviceList *node = g_deviceListHead->next;
      free(g_deviceListHead);
      g_deviceListHead = node;
   }
}

static void ListDevice(void)
{
   DeviceList *node = g_deviceListHead;
   int input, num = 0;

   if (node == NULL) {
      printf("Get no device!\n");
      return;
   }

   CheckDeviceStatus();
   while (node) {
      printf("\n%d: devName=%s\n", ++num, node->device.devName);
      printf("\tdevId=%s\n", node->device.devId);
      printf("\tstatus=%s\n", g_deviceStatus[node->status]);
      node = node->next;
   }

   printf("Input num to auth:");
   scanf_s("%d", &input);
   if (input <= 0 || input >num) {
      printf("error input num\n");
      return;
   }

   node = GetDeviceInfo(input);
   if (node == NULL) {
      printf("GetDeviceInfo fail\n");
      return;
   }

   if (node->status == DEVICE_DISCOVERY) {
      node->requestId = g_requestId;
      node->status = DEVICE_JOINING;
      int ret = HichainGmAddMemberToGroup(&node->device, g_groupId);
      if (ret) {
         printf("HichainGmAddMemberToGroup fail:%d\n", ret);
         node->requestId = ERR_RET;
         node->status = DEVICE_DISCOVERY;
         return;
      }
   }
}

static void PublishSuccess(int publishId)
{
   printf("<PublishSuccess>CB: publish %d done\n", publishId);
}

static void PublishFailed(int publishId, PublishFailReason reason)
{
   printf("<PublishFailed>CB: publish %d failed, reason=%d\n", publishId, (int)reason);
}

static int PublishServiceInterface(void)
{
   PublishInfo info = {
      .publishId = PUBLISH_ID,
      .mode = DISCOVER_MODE_PASSIVE,
      .medium = COAP,
      .freq = LOW,
      .capability = DEFAULT_CAPABILITY,
      .capabilityData = NULL,
      .dataLen = 0,
   };
   IPublishCallback cb = {
      .OnPublishSuccess = PublishSuccess,
      .OnPublishFail = PublishFailed,
   };
   return PublishService(APP_ID, &info, &cb);
}

static void DeviceFound(const DeviceInfo *device)
{
   printf("<DeviceFound>CB: devName=%s", device->devName);

   if (CheckDeviceExist(device)) {
      printf("device:%s udid:%s is already in List\n", device->devName, device->devId);
      return;
   }
   SaveDeviceInfo(device);
}

static void DiscoverySuccess(int subscribeId)
{
   printf("<DiscoverySuccess>CB: discover subscribeId=%d\n", subscribeId);
}

static void DiscoveryFailed(int subscribeId, DiscoveryFailReason reason)
{
   printf("<DiscoveryFailed>CB: discover subscribeId=%d fail, reason=%d\n", subscribeId, (int)reason);
}

static int DiscoveryInterface()
{
   SubscribeInfo info = {
      .subscribeId = PUBLISH_ID,
      .mode = DISCOVER_MODE_ACTIVE,
      .medium = COAP,
      .freq = LOW,
      .isSameAccount = false,
      .isWakeRemote = false,
      .capability = DEFAULT_CAPABILITY,
      .capabilityData = NULL,
      .dataLen = 0,
   };
   IDiscoveryCallback cb = {
      .OnDeviceFound = DeviceFound,
      .OnDiscoverFailed = DiscoveryFailed,
      .OnDiscoverySuccess = DiscoverySuccess,
   };
   return StartDiscovery(APP_ID, &info, &cb);
}

int main()
{
   int ret;
   bool loop = true;

   ret = GetDevUdid(g_udid, MAX_UDID_LEN);
   if (ret) {
      printf("GetDevUdid fail:%d\n", ret);
      return ret;
   }

   ret = HichainInit();
   if (ret) {
      printf("HichainInit fail\n");
      return ret;
   }

   ret = PublishServiceInterface();
   if (ret) {
      printf("PublishService fail, ret=%d\n", ret);
      goto err_PublishServiceInterface;
   }

   ret = DiscoveryInterface();
   if (ret != 0) {
      printf("DiscoveryInterface fail\n");
      goto err_DiscoveryInterface;
   }

   while (loop) {
      printf("\nInput l to list device; Input s to stop:");
      while (true) {
         char c = getchar();
         if (c == 'l') {
            ListDevice();
            continue;
         } else if (c == 's') {
            loop = false;
            break;
         } else if (c == '\n') {
            break;
         } else {
            continue;
         }
      }
   }

   StopDiscovery(APP_ID, PUBLISH_ID);
   FreeDeviceInfo();
err_DiscoveryInterface:
   UnPublishService(APP_ID, PUBLISH_ID);
err_PublishServiceInterface:
   HichainGmUnRegCallback();
   return ret;

}

备注

  • 在HichainInit完成后,可以在任意一端调用HichainGmAddMemberToGroup申请将本端设备添加到对端的群组中。

  • 认证中使用的pin码,分别在两端设备中通过addMemberToGroup函数和HiChainGmOnRuest回调函数接口传入,实际应用中可由用户随机生成。

  • HichainGmAddMemberToGroup认证过程中需要交互的对端信息,如deviceInfo,groupID等,实际应用中可通过软总线的发现能力和认证通道进行数据交互。

客户端使用

聚元 PolyOS 已经为用户提供了编译好的客户端可执行程序 dsoftbus,用户可以根据需求进行二次开发。客户端提供了动态链接库 libsoftbus_client.z.so 以及对应的头文件:

  • 发现:discovery_service.h

  • 组网:softbus_bus_center.h

  • 连接/组网:session.h

  1. discovery_service.h

发现模块头文件,支持应用主动探测和发布的API如下:

PublishService

发布特定服务能力

UnPublishService

取消发布特定服务能力

StartDiscovery

订阅/探测特定服务能力

StopDiscovery

取消订阅特性服务能力

注意

服务能力通过g_capabilityMap数组定义,用户若新增能力需要自定义修改该数组,并重新编译软总线服务端和客户端程序来生效。

  1. softbus_bus_center.h

组网模块头文件,支持获取组网内设备信息API如下:

GetAllNodeDeviceInfo

获取当前组网内所有节点信息

FreeNodeInfo

释放GetAllNodeDeviceInfo返回的节点信息内存

  1. softbus_bus_center.h

连接/传输模块头文件,支持创建session和数据传输API如下:

CreateSessionServer

创建session服务端

RemoveSessionServer

移除session服务端

OpenSession

创建到对端的传输连接(依赖于本端和对端提前创建的SessionServer)

CloseSession

断开传输连接

SendBytes

根据建好的连接ID,进行字节流数据传输

SendMessage

根据建好的连接ID,进行消息数据传输

  1. 应用示例

该示例代码中同时实现了聚元 PolyOS 和 OpenHarmony 设备间的发现、连接、图片收发和图片 TensorFlow Lite 推理和结果反馈功能。客户端程序 dsoftbus.c 具体如下:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <cJSON.h>
#include <fcntl.h>
#include <securec.h>
#include "md5.h"
#include <discovery_service.h>
#include <session.h>
#include <device_auth.h>
#include <parameter.h>
#include <softbus_common.h>
#include <softbus_bus_center.h>

#define APP_ID "hichain_test"
#define DEFAULT_GROUP_NAME "dsoftbus"
#define DEFAULT_PIN_CODE "123456"
#define MAX_UDID_LEN 65
#define MAX_GROUP_LEN 65
#define ERR_RET -1

#define FIELD_ETH_IP "ETH_IP"
#define FIELD_ETH_PORT "ETH_PORT"
#define FIELD_WLAN_IP "WIFI_IP"
#define FIELD_WLAN_PORT "WIFI_PORT"

#define PACKAGE_NAME "softbus_sample"
#define LOCAL_SESSION_NAME "session_test"
#define TARGET_SESSION_NAME "session_test"
#define DEFAULT_CAPABILITY "osdCapability"
#define DEFAULT_SESSION_GROUP "group_test"
#define PUBLISH_ID 123

#define TYPE    "TYPE"
#define NAME    "NAME"
#define LENGTH  "LENGTH"
#define CONTENT "CONTENT"

static int g_sessionId;
static void send_callback(int sessionId ,char *callback);

enum {
   TYPE_MSG = 1,
   TYPE_IMG,
   TYPE_ELSE,
}MessageType;

enum {
   DEVICE_DISCOVERY = 0,
   DEVICE_JOINING,
   DEVICE_ONLINE,
}DeviceStatus;

char *g_deviceStatus[] = {
   "discovery",
   "joining",
   "online",
};

typedef struct DeviceList {
   struct DeviceList *next;
   DeviceInfo device;
   int status;
   int64_t requestId;
} DeviceList;
DeviceList *g_deviceListHead = NULL;

static const DeviceGroupManager *g_hichainGmInstance = NULL;
static char g_udid[MAX_UDID_LEN];
static char g_groupId[MAX_GROUP_LEN];
static int64_t g_requestId = 1;

static const char *GetStringFromJson(const cJSON *obj, const char *key)
{
   cJSON *item;

   if (obj == NULL || key == NULL)
            return NULL;

   item = cJSON_GetObjectItemCaseSensitive(obj, key);
   if (item != NULL && cJSON_IsString(item)) {
            return cJSON_GetStringValue(item);
   } else {
            int len = cJSON_GetArraySize(obj);
            for (int i = 0; i < len; i++) {
                  item = cJSON_GetArrayItem(obj, i);
                  if (cJSON_IsObject(item)) {
                           const char *value = GetStringFromJson(item, key);
                           if (value != NULL)
                                    return value;
                  }
            }
   }
   return NULL;
}

static int HichainSaveGroupID(const char *param)
{
   cJSON *msg = cJSON_Parse(param);
   const char *value = NULL;

   if (msg == NULL) {
            printf("HichainSaveGroupID: cJSON_Parse failed\n");
      return ERR_RET;
   }

   value = GetStringFromJson(msg, FIELD_GROUP_ID);
   if (value == NULL) {
            printf("HichainSaveGroupID:GetStringFromJson failed\n");
            cJSON_Delete(msg);
      return ERR_RET;
   }

   memcpy_s(g_groupId, MAX_GROUP_LEN, value, strlen(value));
   printf("HichainSaveGroupID:groupID=%s\n", g_groupId);

   cJSON_Delete(msg);
   return 0;
}

static void HiChainGmOnFinish(int64_t requestId, int operationCode, const char *returnData)
{
   if (operationCode == GROUP_CREATE && returnData != NULL) {
            printf("create new group finish:requestId=%ld, returnData=%s\n", requestId, returnData);
            HichainSaveGroupID(returnData);
   } else if (operationCode == MEMBER_JOIN) {
      DeviceList *node = g_deviceListHead;
            printf("member join finish:requestId=%ld, returnData=%s\n", requestId, returnData);
      while (node) {
         if (node->requestId != requestId) {
            node = node->next;
            continue;
         }
         node->status = DEVICE_ONLINE;
         break;
      }
   } else {
            printf("<HiChainGmOnFinish>CB:requestId=%ld, operationCode=%d, returnData=%s\n", requestId, operationCode, returnData);
   }
}

static void HiChainGmOnError(int64_t requestId, int operationCode, int errorCode, const char *errorReturn)
{
   DeviceList *node = g_deviceListHead;
   printf("<HiChainGmOnError>CB:requestId=%ld, operationCode=%d, errorCode=%d, errorReturn=%s\n", requestId, operationCode, errorCode, errorReturn);
   while (node) {
      if (node->requestId != requestId) {
         node = node->next;
         continue;
      }
      node->status = DEVICE_DISCOVERY;
      break;
   }
}

static char *HiChainGmOnRuest(int64_t requestId, int operationCode, const char *reqParams)
{
   cJSON *msg = cJSON_CreateObject();
   char *param = NULL;

   printf("<HiChainGmOnRuest>CB:requestId=%ld, operationCode=%d, reqParams=%s", requestId, operationCode, reqParams);

   if (operationCode != MEMBER_JOIN) {
            return NULL;
   }

   if (msg == NULL) {
            printf("HiChainGmOnRuest: cJSON_CreateObject failed\n");
   }

   if (cJSON_AddNumberToObject(msg, FIELD_CONFIRMATION, REQUEST_ACCEPTED) == NULL ||
            cJSON_AddStringToObject(msg, FIELD_PIN_CODE, DEFAULT_PIN_CODE) == NULL ||
            cJSON_AddStringToObject(msg, FIELD_DEVICE_ID, g_udid) == NULL) {
            printf("HiChainGmOnRuest: cJSON_AddToObject failed\n");
            cJSON_Delete(msg);
            return NULL;
   }

   param = cJSON_PrintUnformatted(msg);
   cJSON_Delete(msg);
   return param;
}

static const DeviceAuthCallback g_groupManagerCallback = {
   .onRequest = HiChainGmOnRuest,
   .onError = HiChainGmOnError,
   .onFinish = HiChainGmOnFinish,
};

static int HichainGmRegCallback(void)
{
   return g_hichainGmInstance->regCallback(APP_ID, &g_groupManagerCallback);
}

static void HichainGmUnRegCallback(void)
{
   g_hichainGmInstance->unRegCallback(APP_ID);
}

static int HichainGmGetGroupInfo(char **groupVec, uint32_t *num)
{
   cJSON *msg = cJSON_CreateObject();
   char *param = NULL;
   int ret = ERR_RET;

   if (msg == NULL) {
            printf("HichainGmGetGroupInfo: cJSON_CreateObject failed\n");
      return ret;
   }

   if (cJSON_AddNumberToObject(msg, FIELD_GROUP_TYPE, PEER_TO_PEER_GROUP) == NULL ||
            cJSON_AddStringToObject(msg, FIELD_GROUP_NAME, DEFAULT_GROUP_NAME) == NULL ||
            cJSON_AddNumberToObject(msg, FIELD_GROUP_VISIBILITY, GROUP_VISIBILITY_PUBLIC) == NULL) {
            printf("HichainGmGetGroupInfo: cJSON_AddToObject failed\n");
            goto err_cJSON_Delete;
   }
   param = cJSON_PrintUnformatted(msg);
   if (param == NULL) {
            printf("HichainGmGetGroupInfo: cJSON_PrintUnformatted failed\n");
            goto err_cJSON_Delete;
   }

   ret = g_hichainGmInstance->getGroupInfo(ANY_OS_ACCOUNT, APP_ID, param, groupVec, num);
   if (ret != 0) {
            printf("getGroupInfo failed:%d", ret);
            goto err_getGroupInfo;
   }

err_getGroupInfo:
   cJSON_free(param);
err_cJSON_Delete:
   cJSON_Delete(msg);
   return ret;
}

static void HichainGmDestroyGroupInfo(char **groupVec)
{
   g_hichainGmInstance->destroyInfo(groupVec);
}

static int HichainGmCreatGroup(void)
{
   cJSON *msg = cJSON_CreateObject();
   char *param = NULL;
   int ret = ERR_RET;

   if (msg == NULL)
      return ret;

   if (cJSON_AddNumberToObject(msg, FIELD_GROUP_TYPE, PEER_TO_PEER_GROUP) == NULL ||
            cJSON_AddStringToObject(msg, FIELD_DEVICE_ID, g_udid) == NULL ||
            cJSON_AddStringToObject(msg, FIELD_GROUP_NAME, DEFAULT_GROUP_NAME) == NULL ||
            cJSON_AddNumberToObject(msg, FIELD_USER_TYPE, 0) == NULL ||
            cJSON_AddNumberToObject(msg, FIELD_GROUP_VISIBILITY, GROUP_VISIBILITY_PUBLIC) == NULL ||
            cJSON_AddNumberToObject(msg, FIELD_EXPIRE_TIME, EXPIRE_TIME_MAX) == NULL) {
            printf("HichainGmCreatGroup: cJSON_AddToObject failed\n");
            cJSON_Delete(msg);
      return ret;
   }
   param = cJSON_PrintUnformatted(msg);
   if (param == NULL) {
            printf("HichainGmCreatGroup: cJSON_PrintUnformatted failed\n");
            cJSON_Delete(msg);
      return ret;
   }

   ret = g_hichainGmInstance->createGroup(ANY_OS_ACCOUNT, g_requestId++, APP_ID, param);

   cJSON_free(param);
   cJSON_Delete(msg);
   return ret;
}

static bool HichainIsDeviceInGroup(const char *groupId, const char *devId)
{
   return g_hichainGmInstance->isDeviceInGroup(ANY_OS_ACCOUNT, APP_ID, groupId, devId);
}

static int HichainGmAddMemberToGroup(DeviceInfo *device, const char *groupId)
{
   cJSON *msg = cJSON_CreateObject();
   cJSON *addr = NULL;
   char *param = NULL;
   int ret = ERR_RET;

   if (msg == NULL) {
            printf("HichainGmAddMemberToGroup: cJSON_CreateObject1 failed\n");
      return ret;
   }

   addr = cJSON_CreateObject();
   if (addr == NULL) {
            printf("HichainGmAddMemberToGroup: cJSON_CreateObject2 failed\n");
            goto err_cJSON_CreateObject;
   }

   for (unsigned int i = 0; i < device->addrNum; i++) {
      if (device->addr[i].type == CONNECTION_ADDR_ETH) {
            if (cJSON_AddStringToObject(addr, FIELD_ETH_IP, device->addr[i].info.ip.ip) == NULL ||
                        cJSON_AddNumberToObject(addr, FIELD_ETH_PORT, device->addr[i].info.ip.port) == NULL) {
                  printf("HichainGmAddMemberToGroup: cJSON_AddToObject1 failed\n");
                  goto err_cJSON_AddToObject;
            }
      } else if (device->addr[i].type == CONNECTION_ADDR_WLAN) {
            if (cJSON_AddStringToObject(addr, FIELD_WLAN_IP, device->addr[i].info.ip.ip) == NULL ||
                        cJSON_AddNumberToObject(addr, FIELD_WLAN_PORT, device->addr[i].info.ip.port) == NULL) {
                  printf("HichainGmAddMemberToGroup: cJSON_AddToObject2 failed\n");
                  goto err_cJSON_AddToObject;
            }
      } else {
            printf("unsupport connection type:%d\n", device->addr[i].type);
            goto err_cJSON_AddToObject;
      }
   }

   param = cJSON_PrintUnformatted(addr);
   if (param == NULL) {
            printf("HichainGmAddMemberToGroup: cJSON_PrintUnformatted1 failed\n");
            goto err_cJSON_AddToObject;
   }

   if (cJSON_AddStringToObject(msg, FIELD_GROUP_ID, groupId) == NULL ||
            cJSON_AddNumberToObject(msg, FIELD_GROUP_TYPE, PEER_TO_PEER_GROUP) == NULL ||
            cJSON_AddStringToObject(msg, FIELD_PIN_CODE, DEFAULT_PIN_CODE) == NULL ||
            cJSON_AddStringToObject(msg, FIELD_DEVICE_ID, g_udid) == NULL ||
            cJSON_AddStringToObject(msg, FIELD_GROUP_NAME, DEFAULT_GROUP_NAME) == NULL ||
            cJSON_AddBoolToObject(msg, FIELD_IS_ADMIN, false) == NULL ||
            cJSON_AddStringToObject(msg, FIELD_CONNECT_PARAMS, param) == NULL) {
            printf("HichainGmAddMemberToGroup: cJSON_AddToObject4 failed\n");
            goto err_cJSON_AddToObject1;
   }

   cJSON_free(param);
   param = cJSON_PrintUnformatted(msg);
   if (param == NULL) {
            printf("HichainGmAddMemberToGroup: cJSON_PrintUnformatted failed\n");
            goto err_cJSON_CreateObject;
   }

   ret = g_hichainGmInstance->addMemberToGroup(ANY_OS_ACCOUNT, g_requestId++, APP_ID, param);
   if (ret != 0) {
            printf("addMemberToGroup failed:%d\n", ret);
   }

err_cJSON_AddToObject1:
   cJSON_free(param);
err_cJSON_AddToObject:
   cJSON_Delete(addr);
err_cJSON_CreateObject:
   cJSON_Delete(msg);
   return ret;
}

static int HichainInit(void)
{
   char *groupVec = NULL;
   uint32_t num;
   int ret;

   ret = GetDevUdid(g_udid, MAX_UDID_LEN);
   if (ret) {
            printf("GetDevUdid failed:%d\n", ret);
            return ret;
   }

   ret = InitDeviceAuthService();
   if (ret != 0) {
            printf("InitDeviceAuthService failed:%d\n", ret);
            return ret;
   }

   g_hichainGmInstance = GetGmInstance();
   if (g_hichainGmInstance == NULL) {
            printf("GetGmInstance failed\n");
      ret = ERR_RET;
            goto err_GetGmInstance;
   }

   ret = HichainGmRegCallback();
   if (ret != 0) {
            printf("HichainGmregCallback failed.:%d\n", ret);
            goto err_HichainGmRegCallback;
   }

   ret = HichainGmGetGroupInfo(&groupVec, &num);
   if (ret != 0) {
            printf("HichainGmGetGroupInfo failed:%d\n", ret);
            goto err_HichainGmGetGroupInfo;
   }

   if (num == 0) {
      ret = HichainGmCreatGroup();
         if (ret) {
            printf("HichainGmCreatGroup failed:%d\n", ret);
            goto err_HichainGmCreatGroup;
         }
      }
   else {
         printf("HichainGmGetGroupInfo:num=%u\n", num);
         HichainSaveGroupID(groupVec);
         HichainGmDestroyGroupInfo(&groupVec);
   }

   return 0;

err_HichainGmCreatGroup:
err_HichainGmGetGroupInfo:
   HichainGmUnRegCallback();
err_HichainGmRegCallback:
err_GetGmInstance:
   DestroyDeviceAuthService();
   return ret;
}

static bool CheckDeviceExist(const DeviceInfo *device)
{
   DeviceList *node = g_deviceListHead;

   while (node) {
      if (strcmp(device->devId, node->device.devId) == 0) {
         return true;
      }
      node = node->next;
   }
   return false;
}

static void SaveDeviceInfo(const DeviceInfo *device)
{
   DeviceList *node = malloc(sizeof(DeviceList));

   if (node == NULL) {
      printf("SaveDeviceInfo: malloc failed\n");
      return;
   }

   node->device = *device;
   node->requestId = ERR_RET;
   node->status = DEVICE_DISCOVERY;
   if (g_deviceListHead == NULL) {
      node->next = NULL;
   } else {
      node->next = g_deviceListHead;
   }
   g_deviceListHead = node;
}

static DeviceList *GetDeviceInfo(int idx)
{
   DeviceList *node = g_deviceListHead;
   while (node) {
      if (--idx == 0) {
         return node;
      }
      node = node->next;
   }
   return NULL;
}

static void FreeDeviceInfo()
{
   while (g_deviceListHead) {
      DeviceList *node = g_deviceListHead->next;
      free(g_deviceListHead);
      g_deviceListHead = node;
   }
}

static void PublishSuccess(int publishId)
{
   printf("<PublishSuccess>CB: publish %d done\n", publishId);
}

static void PublishFailed(int publishId, PublishFailReason reason)
{
   printf("<PublishFailed>CB: publish %d failed, reason=%d\n", publishId, (int)reason);
}

static int PublishServiceInterface(void)
{
   PublishInfo info = {
   .publishId = PUBLISH_ID,
         .mode = DISCOVER_MODE_PASSIVE,
         .medium = COAP,
         .freq = LOW,
         .capability = DEFAULT_CAPABILITY,
         .capabilityData = NULL,
         .dataLen = 0,
   };
   IPublishCallback cb = {
         .OnPublishSuccess = PublishSuccess,
         .OnPublishFail = PublishFailed,
   };
   return PublishService(PACKAGE_NAME, &info, &cb);
}

static void UnPublishServiceInterface(void)
{
   int ret = UnPublishService(PACKAGE_NAME, PUBLISH_ID);
   if (ret != 0) {
      printf("UnPublishService failed:%d\n", ret);
   }
}

static void DeviceFound(const DeviceInfo *device)
{
   unsigned int i;
   printf("<DeviceFound>CB: Device has found\n");
   printf("\tdevId=%s\n", device->devId);
   printf("\tdevName=%s\n", device->devName);
   printf("\tdevType=%d\n", device->devType);
   printf("\taddrNum=%d\n", device->addrNum);
   for (i = 0; i < device->addrNum; i++) {
      printf("\t\taddr%d:type=%d,", i + 1, device->addr[i].type);
      switch (device->addr[i].type) {
      case CONNECTION_ADDR_WLAN:
      case CONNECTION_ADDR_ETH:
            printf("ip=%s,port=%d,", device->addr[i].info.ip.ip, device->addr[i].info.ip.port);
            break;
      default:
            break;
      }
      printf("peerUid=%s\n", device->addr[i].peerUid);
   }
   printf("\tcapabilityBitmapNum=%d\n", device->capabilityBitmapNum);
   for (i = 0; i < device->addrNum; i++) {
      printf("\t\tcapabilityBitmap[%d]=0x%x\n", i + 1, device->capabilityBitmap[i]);
   }
   printf("\tcustData=%s\n", device->custData);
   if (CheckDeviceExist(device)) {
      printf("device:%s udid:%s is already in List\n", device->devName, device->devId);
      return;
   }
      SaveDeviceInfo(device);
}

static void DiscoverySuccess(int subscribeId)
{
   printf("<DiscoverySuccess>CB: discover subscribeId=%d\n", subscribeId);
}

static void DiscoveryFailed(int subscribeId, DiscoveryFailReason reason)
{
   printf("<DiscoveryFailed>CB: discover subscribeId=%d failed, reason=%d\n", subscribeId, (int)reason);
}

static int DiscoveryInterface()
{
   SubscribeInfo info = {
   .subscribeId = PUBLISH_ID,
         .mode = DISCOVER_MODE_ACTIVE,
         .medium = COAP,
         .freq = LOW,
         .isSameAccount = false,
         .isWakeRemote = false,
         .capability = DEFAULT_CAPABILITY,
         .capabilityData = NULL,
         .dataLen = 0,
   };
   IDiscoveryCallback cb = {
         .OnDeviceFound = DeviceFound,
         .OnDiscoverFailed = DiscoveryFailed,
         .OnDiscoverySuccess = DiscoverySuccess,
   };
   return StartDiscovery(PACKAGE_NAME, &info, &cb);
}

static void StopDiscoveryInterface(void)
{
   int ret = StopDiscovery(PACKAGE_NAME, PUBLISH_ID);
   if (ret) {
         printf("StopDiscovery failed:%d\n", ret);
   }
}

static int SessionOpened(int sessionId, int result)
{
   printf("<SessionOpened>CB: session %d open result:%d\n", sessionId, result);
   if (result == 0) {
         g_sessionId = sessionId;
   }

   return result;
}

static void SessionClosed(int sessionId)
{
   printf("<SessionClosed>CB: session %d closed\n", sessionId);
}

static int md5_file_calc(char *filename, char *dest)
{
   int i = 0;
   int filelen = 0;
   int read_len = 0;
   char temp[8] = {0};
   char hexbuf[128] = {0};
   unsigned char decrypt[16] = {0};
   unsigned char decrypt32[64] = {0};
   MD5_CTX md5;
   char fw_path[128];

   int fd;

   fd = open(filename, O_RDWR);
   if (fd < 0)
   {
      printf("%s not exist\n", filename);
      return -1;
   }

   MD5Init(&md5);
   while (1)
   {
      read_len = read(fd, hexbuf, sizeof(hexbuf));
      if (read_len < 0)
      {
            close(fd);
            return -1;
      }
      if (read_len == 0)
      {
            break;
      }
      filelen += read_len;
      MD5Update(&md5, (unsigned char *)hexbuf, read_len);
   }

   MD5Final(&md5, decrypt);
   strcpy((char *)decrypt32, "");

   for (i = 0; i < 16; i++)
   {
      sprintf(temp, "%02x", decrypt[i]);
      strcat((char *)decrypt32, temp);
   }
   strcpy(dest, decrypt32);

   printf("md5:%s len=%d\n", dest, filelen);
   close(fd);

   return filelen;
}

static void ByteRecived(int sessionId, const void *data, unsigned int dataLen)
{
   //创建文件
   FILE *fp = NULL;
   FILE *cp = NULL;
   int  msg_type,ret;
   char *content,*file_name;
   char *param = NULL;
   static int file_length = 0;
   char callback[1024] = {0};
   static char name[64] = {0};
   static bool isFile = false;

   if(isFile)//接收文件内容
   {
      fp = fopen(name,"w");

      if (fwrite((const char *)data,file_length,1,fp) == 1)
      {
         printf("文件 %s 写入成功!\n",name);
         fflush(fp);

         //执行文件操作指令
         cp = popen("/usr/share/tensorflow/lite/examples/label_image/label_image --tflite_model /usr/share/tensorflow/lite/examples/label_image/mobilenet_v1_1.0_224.tflite --labels /usr/share/tensorflow/lite/examples/label_image/labels.txt --image ./hcg.png 2>&1", "r");
         fread(callback,1,sizeof(callback)-1,cp);
         send_callback(g_sessionId,callback);
      }
      else
      {
         printf("文件 %s 写入失败!\n",name);
      }

      pclose(cp);
      fclose(fp);
      isFile = false;
   }
   else//接收json数据
   {
      cJSON *root = cJSON_Parse((const char *)data);

      /*获取消息类型*/
      cJSON * msg = cJSON_GetObjectItem(root, TYPE);
      msg_type = cJSON_GetNumberValue(msg);

      /*获取消息/文件内容*/
      msg = cJSON_GetObjectItem(root, CONTENT);
      content = cJSON_GetStringValue(msg);

      if(msg_type == 1)//处理消息的接收
      {
         printf("<ByteRecived>CB: msg_type is %d,content is %s\n",msg_type,content);
      }
      else if(msg_type == 2)//处理文件的接收
      {
         isFile = true;

         /*获取文件名称*/
         msg = cJSON_GetObjectItem(root, NAME);
         file_name = cJSON_GetStringValue(msg);
         strcpy(name, file_name);

         /*获取文件长度*/
         msg = cJSON_GetObjectItem(root, LENGTH);
         file_length = cJSON_GetNumberValue(msg);

         printf("<ByteRecived>CB: msg_type is %d,name is %s,file_length is %d,content is %s\n",msg_type,name,file_length,content);
      }
      else//其他
      {
         printf("<ByteRecived>CB: msg_type error\n");
      }

      cJSON_Delete(root);
   }
}

static void MessageReceived(int sessionId, const void *data, unsigned int dataLen)
{
      printf("<MessageReceived>CB: session %d received %u bytes message=%s\n", sessionId, dataLen, (const char *)data);
}

static int CreateSessionServerInterface(void)
{
      const ISessionListener sessionCB = {
               .OnSessionOpened = SessionOpened,
               .OnSessionClosed = SessionClosed,
               .OnBytesReceived = ByteRecived,
               .OnMessageReceived = MessageReceived,
      };

      return CreateSessionServer(PACKAGE_NAME, LOCAL_SESSION_NAME, &sessionCB);
}

static void RemoveSessionServerInterface(void)
{
      int ret = RemoveSessionServer(PACKAGE_NAME, LOCAL_SESSION_NAME);
      if (ret) {
               printf("RemoveSessionServer failed:%d\n", ret);
      }
}

static int OpenSessionInterface(const char *peerNetworkId)
{
      SessionAttribute attr = {
               .dataType = TYPE_BYTES,
               .linkTypeNum = 1,
               .linkType[0] = LINK_TYPE_WIFI_WLAN_2G,
               .attr = {RAW_STREAM},
      };

      return OpenSession(LOCAL_SESSION_NAME, TARGET_SESSION_NAME, peerNetworkId, DEFAULT_SESSION_GROUP, &attr);
}

static void CloseSessionInterface(int sessionId)
{
      CloseSession(sessionId);
}

static int GetAllNodeDeviceInfoInterface(NodeBasicInfo **dev)
{
      int ret, num;

      ret = GetAllNodeDeviceInfo(PACKAGE_NAME, dev, &num);
      if (ret) {
               printf("GetAllNodeDeviceInfo failed:%d\n", ret);
               return -1;
      }

      printf("<GetAllNodeDeviceInfo>return %d Node\n", num);
      for (int i = 0; i < num; i++) {
               printf("<num %d>deviceName=%s\n", i + 1, dev[i]->deviceName);
               printf("\tnetworkId=%s\n", dev[i]->networkId);
               printf("\tType=%d\n", dev[i]->deviceTypeId);
      }

      return num;
}

static void FreeNodeInfoInterface(NodeBasicInfo *dev)
{
      FreeNodeInfo(dev);
}

static void send_callback(int sessionId ,char *callback)
{
      cJSON *msg = cJSON_CreateObject();
      char *param = NULL;

      if (msg == NULL) {
         printf("send_callback: cJSON_CreateObject failed\n");
      }

      if (cJSON_AddNumberToObject(msg, TYPE, TYPE_MSG)     == NULL ||
            cJSON_AddStringToObject(msg, NAME, "")           == NULL ||
         cJSON_AddNumberToObject(msg, LENGTH, 0)          == NULL ||
         cJSON_AddStringToObject(msg, CONTENT, callback)  == NULL)
      {
            printf("send_callback: cJSON_AddToObject failed\n");
      }

      param = cJSON_PrintUnformatted(msg);
      if (param == NULL)
      {
            printf("send_callback: cJSON_PrintUnformatted failed\n");
      }

      SendBytes(sessionId, param, strlen(param) + 1);

      printf("send_callback: param is %s\n",param);
      cJSON_free(param);
      cJSON_Delete(msg);
}

static void md5_file(void)
{
   int  filelen;
   char md5_file[64] = {0};
   char md5_str[64] = {0};

   printf("请输入需要MD5校验的文件名:");
   if(scanf("%s",md5_file))
   {
      printf("输入完毕!\n");
   }
   getchar();//过滤回车

   filelen = md5_file_calc(md5_file, md5_str);
   if (filelen < 0)
   {
      printf("md5_file: calc_md5 fail\n");
      return;
   }
}

static void softbus_file(int sessionId)
{
      char file_name[64] = {0};
      char file_md5[64] = {0};
      char *file_data;
      FILE *fp = NULL;
      int ret, file_size;
      cJSON *msg = cJSON_CreateObject();
      char *param = NULL;

      if (msg == NULL) {
         printf("softbus_file: cJSON_CreateObject failed\n");
      }

      printf("请输入需要传输的文件名:");
      if(scanf("%s",file_name)){
         printf("输入完毕!\n");
      }
      getchar();//过滤回车

      fp = fopen(file_name, "rb");
      file_size = md5_file_calc(file_name, file_md5);
      file_data = (char*)malloc((file_size+1)*sizeof(char));
      fread(file_data,1,file_size, fp);
      file_data[file_size]= '\0';

      if (cJSON_AddNumberToObject(msg, TYPE, TYPE_IMG)     == NULL ||
            cJSON_AddStringToObject(msg, NAME, file_name)    == NULL ||
         cJSON_AddNumberToObject(msg, LENGTH, file_size)  == NULL ||
         cJSON_AddStringToObject(msg, CONTENT, "")        == NULL)
      {
            printf("softbus_file: cJSON_AddToObject failed\n");
      }

      param = cJSON_PrintUnformatted(msg);
      if (param == NULL)
      {
            printf("softbus_file: cJSON_PrintUnformatted failed\n");
      }

      SendBytes(sessionId, param, strlen(param) + 1);
      SendBytes(sessionId, file_data, file_size);

      printf("softbus_file: param is %s\n",param);
      cJSON_free(param);
      cJSON_Delete(msg);

      free(file_data);
      fflush(fp);
      fclose(fp);
}

static void softbus_msg(int sessionId)
{
      char message[1024] = {0};
      cJSON *msg = cJSON_CreateObject();
      char *param = NULL;

      if (msg == NULL) {
         printf("softbus_msg: cJSON_CreateObject failed\n");
      }

      printf("请输入需要传输的内容:");
      if(scanf("%s",message)){
         printf("输入完毕!\n");
      }
      getchar();//过滤回车

      if (cJSON_AddNumberToObject(msg, TYPE, TYPE_MSG)     == NULL ||
            cJSON_AddStringToObject(msg, NAME, "")           == NULL ||
         cJSON_AddNumberToObject(msg, LENGTH, 0)          == NULL ||
         cJSON_AddStringToObject(msg, CONTENT, message)   == NULL)
      {
            printf("softbus_msg: cJSON_AddToObject failed\n");
      }

      param = cJSON_PrintUnformatted(msg);
      if (param == NULL)
      {
            printf("softbus_msg: cJSON_PrintUnformatted failed\n");
      }

      SendBytes(sessionId, param, strlen(param) + 1);

      printf("softbus_msg: param is %s\n",param);
      cJSON_free(param);
      cJSON_Delete(msg);
}

static void softbus_test(int sessionId)
{
      char cData[] = "PolyOS-Dsoftbus-Test";
      cJSON *msg = cJSON_CreateObject();
      char *param = NULL;

      if (msg == NULL) {
         printf("softbus_test: cJSON_CreateObject failed\n");
      }

      if (cJSON_AddNumberToObject(msg, TYPE, TYPE_MSG)     == NULL ||
            cJSON_AddStringToObject(msg, NAME, "")           == NULL ||
         cJSON_AddNumberToObject(msg, LENGTH, 0)          == NULL ||
         cJSON_AddStringToObject(msg, CONTENT, cData)     == NULL)
      {
            printf("softbus_test: cJSON_AddToObject failed\n");
      }

      param = cJSON_PrintUnformatted(msg);
      if (param == NULL)
      {
            printf("softbus_test: cJSON_PrintUnformatted failed\n");
      }

      SendBytes(sessionId, param, strlen(param) + 1);

      printf("softbus_test: param is %s\n",param);
      cJSON_free(param);
      cJSON_Delete(msg);
}

int main(int argc, char **argv)
{
      NodeBasicInfo *dev = NULL;
      bool loop = true;
      int ret,sessionId;

      ret = CreateSessionServerInterface();
      if (ret) {
               printf("CreateSessionServer failed, ret=%d\n", ret);
               return ret;
      }

      ret = PublishServiceInterface();
      if (ret) {
               printf("PublishService failed, ret=%d\n", ret);
               goto err_PublishServiceInterface;
      }

      ret = DiscoveryInterface();
      if (ret) {
               printf("DiscoveryInterface failed, ret=%d\n", ret);
               goto err_DiscoveryInterface;
      }

      ret = GetAllNodeDeviceInfoInterface(&dev);
      if (ret <= 0) {
               printf("GetAllNodeDeviceInfoInterface failed, ret=%d\n", ret);
               return ret;
      }

      g_sessionId = -1;
      sessionId = OpenSessionInterface(dev[0].networkId);
      if (sessionId < 0) {
               printf("OpenSessionInterface fail, ret=%d\n", sessionId);
               goto err_OpenSessionInterface;
      }

      while (loop) {
               printf("\n Input t to dsoftbus test, Input k to send file, Input m to send message,Input c to get md5, Input s to stop:");
               char op = getchar();
               getchar();//过滤回车
               switch(op) {
                  case 'k':
                     softbus_file(g_sessionId);
                     continue;
                  case 'm':
                     softbus_msg(g_sessionId);
                     continue;
                  case 't':
                     softbus_test(g_sessionId);
                     continue;
                  case 'c':
                     md5_file();
                     continue;
                  case 's':
                     loop = false;
                     break;
                  case '\n':
                     break;
                     default:
                     continue;
               }
      }

      StopDiscoveryInterface();
      FreeDeviceInfo();
      CloseSessionInterface(sessionId);
err_OpenSessionInterface:
      FreeNodeInfoInterface(dev);
err_DiscoveryInterface:
      UnPublishServiceInterface();
err_PublishServiceInterface:
      RemoveSessionServerInterface();
      return 0;
}