WISE-Agent Sample Client

From ESS-WIKI
Jump to: navigation, search

Advantech provides a WISE Agent Sample to demonstrate how to implement a custom application to connect to RMM Server.


Architecture

In WISEAgent, the SAClient is the main entry library. The SAClient is responsible for several jobs, include:

  • Exchange information between a device and RMM Server.
  • Maintain the MQTT connection.
  • Dynamic load and interact with Core Management.

In Custom Application, users only need to include the SAClient Library. And provide the connection infomation defined in Configuration structure, the platform information defined in Platform Profiler structure.

RTENOTITLE

SAClient APIs

List

int saclient_initialize(susiaccess_agent_conf_body_t * config, susiaccess_agent_profile_body_t * profile, void * loghandle); 
Description
  • General initialization of the SAClient API. Prior to calling any SAClient API functions, the library needs to be initialized by calling this function.
  • The status code for all SAClient API function will be saclient_no_init unless this function is called.

Parameters

  • config[POINTER]
    • the structure to describe how to comnnect to server.
  • profile[POINTER]
    • the structure to describe the platform information of target device.
  • loghandle[POINTER]
    • the file handle for log library.

Return Values

  • saclient_success: on success.
  • saclient_false: initialize failed
  • saclient_config_error: the input config data were invalid.
  • saclient_profile_error: the input profile data were invalid.

Example

Reference to saclient_connection_callback_set().



void saclient_uninitialize();
Description
  • General function to uninitialize the SAClient API library that should be called before program exit.

Parameters

  • None

Return Values

  • None

Example

Reference to saclient_connection_callback_set().



int saclient_connect();
Description
  • Connect to server that defined in Configuration data of saclient_initialize parameters.

Parameters

  • None

Return Values

  • saclient_success: on success.
  • saclient_no_init: not initialized or init failed before.
  • saclient_network_sock_timeout: connect timeout
  • saclient_network_sock_error: create socket failed
  • saclient_report_agentinfo_error: send agentinfo failed.
  • saclient_send_willmsg_error: send will message failed
  • saclient_false: connect failed

Example

Reference to saclient_connection_callback_set().



void saclient_disconnect();
Description
  • Disconnect from server.

Parameters

  • None

Return Values

  • None

Example

Reference to saclient_connection_callback_set().



void saclient_connection_callback_set(SACLIENT_CONNECTED_CALLBACK on_connect, SACLIENT_LOSTCONNECT_CALLBACK on_lost_connect, SACLIENT_DISCONNECT_CALLBACK on_disconnect);
Description
  • Send message wrapped in packet structure to server on specific MQTT topic.

Parameters

  • on_connect[POINTER]
    • functin pointer to handle on connected event.
  • on_lost_connect[POINTER]
    • functin pointer to handle on lost connect event.
  • on_disconnect[POINTER]
    • functin pointer to handle on disconnect event.

Return Values

  • None.

Example

#include "SAClient.h"

/*agent connected callback function*/
void on_connect_cb()
{
	printf("CB_Connected ");
}
 
/*agent lost connect callback function*/
void on_lost_connect_cb()
{
	printf("CB_Lostconnect ");
}
 
/*agent disconnect callback function*/
void on_disconnect_cb()
{
	printf("CB_Disconnect ");
}

int main (int argc, char *argv[])
{
	int iRet = 0;
	
	/*agent configuration structure: define how does the agent connect to Server*/
	susiaccess_agent_conf_body_t config;
 	/*Pre-set Agent Config struct*/

	/*agent profile structure: define agent platform information*/
	susiaccess_agent_profile_body_t profile;
	/*Pre-set Agent Profile struct*/
  
	/*Initialize SAClient with Agent Configure and Profile structure, and the Log File Handle*/
	iRet = saclient_initialize(&config, &profile, NULL);

	saclient_connection_callback_set(on_connect_cb, on_lost_connect_cb, on_disconnect_cb);
 
	/*start connect to server, server is defined in agent config*/
	iRet = saclient_connect();
 
	/*disconnect from server*/
	saclient_disconnect();
	/*release SAClient resource*/
	saclient_uninitialize();
	return iRet;
}


int saclient_publish(char const * topic, int qos, int retain, susiaccess_packet_body_t const * pkt);
Description
  • Send message wrapped in packet structure to server on specific MQTT topic.

Parameters

  • topic[POINTER]
    • MQTT topic string
  • qos[NUMBER]
    • MQTT qos level from 0 to 2.
  • retain[NUMBER]
    • MQTT retain flag, 0:disable, 1:enable.
  • pkt[POINTER]
    • the packet structure pointer.

Return Values

  • saclient_success: on success.
  • saclient_no_init: not initialized or init failed before.
  • saclient_no_connnect: not connect before or lost connection.
  • saclient_false: connect failed.

Example

#include "SAClient.h"

int main (int argc, char *argv[])
{
    char topicStr[128] = {0};
    susiaccess_packet_body_t pkt;

    /*Send test packet to specific topic*/
    sprintf(topicStr, "/cagent/admin/%s/testreq", profile.devId);
    strcpy(pkt.devId, profile.devId);
    strcpy(pkt.handlerName, "Test");
    pkt.requestID = 0;
    pkt.cmd = 0;
    pkt.content = (char*)malloc(strlen("{\"Test\":100}")+1);
    memset(pkt.content, 0, strlen("{\"Test\":100}")+1);
    strcpy(pkt.content, "{\"Test\":100}");
    saclient_publish(topicStr, 0, false, &pkt);
    free(pkt.content);
}


int saclient_subscribe(char const * topic, int qos, SACLIENT_MESSAGE_RECV_CALLBACK msg_recv_callback);
Description
  • Register a callback function to receive message from server on specific MQTT topic.

Parameters

  • topic[POINTER]
    • MQTT topic string
  • qos[NUMBER]
    • MQTT qos level from 0 to 2.
  • msg_recv_callback[POINTER]
    • functin pointer to handle on message receive event.

Return Values

  • saclient_success: on success.
  • saclient_no_init: not initialized or init failed before.
  • saclient_no_connnect: not connect before or lost connection.
  • saclient_false: connect failed.

Example

#include "SAClient.h"

/*agent received message callback function*/
void on_msgrecv(char* topic, susiaccess_packet_body_t *pkt, void *pRev1, void* pRev2)
{
    /*user can process received command here*/
    printf("Packet received, %s\r\n", pkt->content);
}

int main (int argc, char *argv[])
{
    char topicStr[128] = {0};

    /* Add subscribe topic Callback*/
    sprintf(topicStr, "/cagent/admin/%s/testreq", profile.devId);
    saclient_subscribe(topicStr, 0, on_msgrecv);
}


int saclient_getsocketaddress(char* clientip, int size);
Description
  • Get local IP address that connect to server.

Parameters

  • clientip [POINTER]
    • IP address string.
  • size[NUMBER]
    • the size of IP address.

Return Values

  • saclient_success: on success.
  • saclient_no_init: not initialized or init failed before.
  • saclient_no_connnect: not connect before or lost connection.
  • saclient_false: connect failed.

Example

#include "SAClient.h"
int main (int argc, char *argv[])
{
	int iRet = 0;
	
	/*agent configuration structure: define how does the agent connect to Server*/
	susiaccess_agent_conf_body_t config;
 	/*Pre-set Agent Config struct*/

	/*agent profile structure: define agent platform information*/
	susiaccess_agent_profile_body_t profile;
	/*Pre-set Agent Profile struct*/
  
	/*Initialize SAClient with Agent Configure and Profile structure, and the Log File Handle*/
	iRet = saclient_initialize(&config, &profile, NULL);
 
	if(iRet != saclient_success)
	{
		printf("Unable to initialize AgentCore.");
		return iRet;
	}
 
	/*start connect to server, server is defined in agent config*/
	iRet = saclient_connect();
 
	if(iRet != saclient_success){
		printf("sampleagent Unable to connect to broker.");
			
	} else {
		char localip[256]={0};
		saclient_getsocketaddress(localip, sizeof(localip));
		printf("sampleagent Connected localip: %s", localip);
	}
 
	/*disconnect from server*/
	saclient_disconnect();
	/*release SAClient resource*/
	saclient_uninitialize();
	return iRet;
}

Callback Function

typedef void (*SACLIENT_MESSAGE_RECV_CALLBACK)(char* topic, susiaccess_packet_body_t *pkt, void *pRev1, void* pRev2);
Description
  • define the message receive callback function.

Parameters

  • topic[POINTER]
    • MQTT topic string
  • pkt[POINTER]
    • the packet structure pointer.
  • pRev1[POINTER]
    • preserved pointer.
  • pRev2[POINTER]
    • preserved pointer.

Return Values

  • None.


typedef void (*SACLIENT_CONNECTED_CALLBACK)();
Description
  • define the on connected callback function.

Parameters

  • None

Return Values

  • None.


typedef void (*SACLIENT_LOSTCONNECT_CALLBACK)();
Description
  • define the on lost connect callback function.

Parameters

  • None

Return Values

  • None.


typedef void (*SACLIENT_DISCONNECT_CALLBACK)();
Description
  • define the on disconnect callback function.

Parameters

  • None

Return Values

  • None.

Configuration Structure

typedef struct {
	/*Connection Mode*/
	char runMode[DEF_RUN_MODE_LENGTH];
	char autoStart[DEF_ENABLE_LENGTH];

	/*Connection Info*/
	char serverIP[DEF_MAX_STRING_LENGTH];
	char serverPort[DEF_PORT_LENGTH];
	char serverAuth[DEF_USER_PASS_LENGTH];

	tls_type tlstype;
	/*TLS*/
	char cafile[DEF_MAX_PATH];
	char capath[DEF_MAX_PATH];
	char certfile[DEF_MAX_PATH];
	char keyfile[DEF_MAX_PATH];
	char cerpasswd[DEF_USER_PASS_LENGTH];
	/*pre-shared-key*/
	char psk[DEF_USER_PASS_LENGTH];
	char identity[DEF_USER_PASS_LENGTH];
	char ciphers[DEF_MAX_CIPHER];
}susiaccess_agent_conf_body_t;
Description
  • The structure for agent connect configuration, defined in susiaccess_def.h.

Parameters

  • runMode[POINTER]
    • default is remote.
    • no other mode in WISE Agent version 3.x
  • autoStart[POINTER]
    • The Agent will reconnect to server automatically, default is True.
  • serverIP[POINTER]
    • indicate the server URL or IP Address
  • serverPort[POINTER]
    • Server (MQTT Broker) listen port,
    • in WISE Agent version 3.1 or later the default port is 1883
    • in WISE Agent version 3.0 the default port is 10001.
  • serverAuth[POINTER]
    • Server (MQTT Broker) authentication string.
    • The string is encode from <ID>:<PASS>.
    • It worked on SSL Mode.
  • tlstype [NUMBER]
    • define the TLS (SSL) mode:
      • tls_type_none
      • tls_type_tls
      • tls_type_psk
  • cafile[POINTER]
    • the filepath of SSL Certificate Authority file in tls_type_tls mode.
  • capath[POINTER]
    • the path of SSL Certificate Authority files in tls_type_tls mode.
  • certfile[POINTER]
    • the filepath of SSL Certificate file in tls_type_tls mode.
  • keyfile[POINTER]
    • the filepath of SSL Key file in tls_type_tls mode.
  • cerpasswd[POINTER]
    • the string of SSL Certificate file password in tls_type_tls mode.
  • psk[POINTER]
    • the string of SSL pre-share key in tls_type_psk mode.
  • identity[POINTER]
    • the unique string of SSL identity in tls_type_psk mode.
  • ciphers[POINTER]
    • the supported cipher list in tls_type_psk mode.

Profile Structure

typedef struct {
	/*Agent Info*/
	char version[DEF_MAX_STRING_LENGTH];
	char hostname[DEF_HOSTNAME_LENGTH];
	char devId[DEF_DEVID_LENGTH];
	char sn[DEF_SN_LENGTH];
	char mac[DEF_MAC_LENGTH];
	char lal[DEF_LAL_LENGTH];
	char account[DEF_USER_PASS_LENGTH];
	char passwd[DEF_USER_PASS_LENGTH];
	char workdir[DEF_MAX_PATH];

	/*Custom Info*/
	char type[DEF_MAX_STRING_LENGTH];
	char product[DEF_MAX_STRING_LENGTH];
	char manufacture[DEF_MAX_STRING_LENGTH];

	/*OS Info*/
	char osversion[DEF_OSVERSION_LEN];
	char biosversion[DEF_VERSION_LENGTH];
	char platformname[DEF_FILENAME_LENGTH];
	char processorname[DEF_PROCESSOR_NAME_LEN];
	char osarchitect[DEF_FILENAME_LENGTH];
	long totalmemsize;
	char maclist[DEF_MAC_LENGTH*16];
	char localip[DEF_MAX_STRING_LENGTH];
}susiaccess_agent_profile_body_t;
Description
  • The structure for  platform description, defined in susiaccess_def.h.

Parameters

  • version[POINTER]
    • The version fo the application.
  • hostname [POINTER]
    • The name of target device ro agent.
  • devId[POINTER]
    • The Unique ID of the target device or agent.
  • sn[POINTER]
    • The target device serial number
  • mac[POINTER]
    • the MAC Address of first ethernet or wireless card.
  • type[POINTER]
    • the agent type, defualt is IPC.
    • User can define their own type for customization.
  • produce[POINTER]
    • the product name.
  • manufacture[POINTER]
    • the manufacture name.
  • osversion[POINTER]
    • the OS version of target device.
  • biosversion[POINTER]
    • the BIOS version of target device.
  • platformname[POINTER]
    • the platform (board) name of target device.
  • processorname[POINTER]
    • the processor name of target device.
  • osarchitect[POINTER]
    • the OS architecture name of target device.
  • totalmemsize [NUMBER]
    • the OS recognized total memory size of target device.
  • maclist[POINTER]
    • list all the ethernet and wireless card MAC Address.
  • localip[POINTER]
    • the local IP of target device.
  • account[POINTER]
    • bind the device or anget to the sepcific account, default is anonymous.
  • passwd[POINTER]
    • the encrypted password string of account.
  • workdir[POINTER]
    • current executable binary file location.

Packet Structure

 typedef struct{
	int cmd;
	int requestID;      /**< Callback request id */
	char devId[DEF_DEVID_LENGTH]; /**< Agent device id */
	char handlerName[MAX_TOPIC_LEN];
	char* content;     /**< Callback request content */
	packet_type type;
}susiaccess_packet_body_t;
Description
  • the structure for transmit packet, defined in susiaccess_def.h.

Parameters

  • cmd [NUMBER]
    • The command id defined in Plugins (Handlers).
  • requestID [NUMBER]
    • The unique ID for Plugins (Handlers),
    • No used for V3.1 or later version, preserved for V3.0.
  • devId[POINTER]
    • The target device or Agent ID.
  • handlerName[POINTER]
    • The string of Plugin (Handler) Name.
  • content[POINTER]
    • the string of packet content message.
  • type [NUMBER]
    • the packet type:
      • pkt_type_susiaccess: common RMM message packet wrapped with RMM pre-defined header.
      • pkt_type_custom: customized message packet without wrapped with RMM header.

Client Sample Code

#include "stdafx.h"
#include <SAClient.h>
#include <Windows.h>
#include <Log.h>
/*agent connected callback function*/
void on_connect_cb()
{
	SUSIAccessAgentLog(Normal, "CB_Connected ");
}

/*agent lost connect callback function*/
void on_lost_connect_cb()
{
	SUSIAccessAgentLog(Normal, "CB_Lostconnect ");
}

/*agent disconnect callback function*/
void on_disconnect_cb()
{
	SUSIAccessAgentLog(Normal, "CB_Disconnect ");
}

/*agent received message callback function*/
void on_msgrecv(char* topic, susiaccess_packet_body_t *pkt, void *pRev1, void* pRev2)
{
	/*user can process received command here*/
	SUSIAccessAgentLog(Normal, "Packet received, %s\r\n", pkt->content);
}

int main(int argc, char *argv[])
{
	int iRet = 0;
	char moudlePath[MAX_PATH] = {0};
	
	/*agent configuration structure: define how does the agent connect to Server*/
	susiaccess_agent_conf_body_t config;

	/*agent profile structure: define agent platform information*/
	susiaccess_agent_profile_body_t profile;

	memset(moudlePath, 0 , sizeof(moudlePath));
	util_module_path_get(moudlePath);
		
	// Initialize Log Library
	SUSIAccessAgentLogHandle = InitLog(moudlePath);
	SUSIAccessAgentLog(Normal, "Current path: %s", moudlePath);

	// Pre-set Agent Config struct
	memset(&config, 0 , sizeof(susiaccess_agent_conf_body_t));
	strcpy(config.runMode,"remote"); //runMode default is remote. There are no other mode in WISE Agent version 3.x
	strcpy(config.autoStart,"True"); //autoStart default is True. The Agent will reconnect to server automatically.
	strcpy(config.serverIP,"dev-wisepaas.eastasia.cloudapp.azure.com"); //serverIP indicate the server URL or IP Address
	strcpy(config.serverPort,"1883"); //serverPort indocate the server (MQTT Broker) listen port, default is 1883 in WISE Agent version 3.1 or later, WISE Agent version 3.0 is 10001.
	strcpy(config.serverAuth,"fENl4B7tnuwpIbs61I5xJQ=="); //serverAuth is the server (MQTT Broker) authentication string. the string is encode from <ID>:<PASS>. It only worked on SSL Mode.
	config.tlstype = tls_type_none; //tlstype define the TLS (SSL) mode
	switch(config.tlstype)
	{
	case tls_type_none: //disable TLS (SSL).
		break;
	case tls_type_tls: //setup TLS with certificate file.
		{
			strcpy(config.cafile, "ca.crt");
			strcpy(config.capath, "");
			strcpy(config.certfile, "server.crt");
			strcpy(config.keyfile, "server.key");
			strcpy(config.cerpasswd, "123456");
		}
		break;
	case tls_type_psk: //setup TLS with pre share key.
		{
			strcpy(config.psk, "");
			strcpy(config.identity, "SAClientSample");
			strcpy(config.ciphers, "");
		}
		break;
	}

	// Pre-set Agent Profile struct
	memset(&profile, 0 , sizeof(susiaccess_agent_profile_body_t));
	snprintf(profile.version, DEF_VERSION_LENGTH, "%d.%d.%d.%d", 3, 1, 0, 0);  //version indicate the version fo the application.
	strcpy(profile.hostname,"SAClientSample"); //hostname indicate the name of target device ro agent.
	strcpy(profile.devId,"000014DAE996BE04"); //devId is the Unique ID of the target device or agent.
	strcpy(profile.sn,"14DAE996BE04"); //sn indicate the device serial number.
	strcpy(profile.mac,"14DAE996BE04"); //mac indicate the MAC Address of first ethernet or wireless card.
	strcpy(profile.type,"IPC"); //type indicate the agent type, defualt is IPC. User can define their own type for customization.
	strcpy(profile.product,"Sample Agent"); //produce indicate the product name
	strcpy(profile.manufacture,"test"); //manufacture indicate the manufacture name
	strcpy(profile.osversion,"NA"); //osversion indicate the OS version of target device
	strcpy(profile.biosversion,"NA"); //biosversion indicate the BIOS version of target device
	strcpy(profile.platformname,"NA"); //platformname indicate the platform (board) name of target device
	strcpy(profile.processorname,"NA"); //processorname indicate the processor name of target device
	strcpy(profile.osarchitect,"NA"); //osarchitect indicate the OS architecture name of target device
	profile.totalmemsize = 40832; //totalmemsize indicate the OS recognized total memory size of target device
	strcpy(profile.maclist,"14DAE996BE04"); //maclist list all the ethernet and wireless card MAC Address.
	strcpy(profile.localip,"172.21.73.151"); //localip indicate the local IP of target device
	strcpy(profile.account,"anonymous"); //account bind the device or anget to the sepcific account, default is anonymous.
	strcpy(profile.passwd,""); //passwd indicate the encrypted password of account.
	strcpy(profile.workdir, moudlePath); //workdir indicate current executable binary file location.


	/*Initialize SAClient with Agent Configure and Profile structure, and the Log File Handle*/
	iRet = saclient_initialize(&config, &profile, SUSIAccessAgentLogHandle);

	if(iRet != saclient_success)
	{
		SUSIAccessAgentLog(Error, "Unable to initialize AgentCore.");
		goto EXIT;
	}

	SUSIAccessAgentLog(Normal, "Agent Initialized");

	/*register the conect, lost connect and disconnect callback function*/
	saclient_connection_callback_set(on_connect_cb, on_disconnect_cb, on_disconnect_cb);

	SUSIAccessAgentLog(Normal, "Agent Set Callback");
	
	/*start connect to server, server is defined in agent config*/
	iRet = saclient_connect();

	if(iRet != saclient_success){
		SUSIAccessAgentLog(Error, "sampleagent Unable to connect to broker.");
		goto EXIT;
	} else {
		SUSIAccessAgentLog(Normal, "sampleagent Connect to broker: %s", config.serverIP);
	}
	
	{
		
		char topicStr[128] = {0};
		susiaccess_packet_body_t pkt;

		/* Add  subscribe topic Callback*/
		sprintf(topicStr, "/cagent/admin/%s/testreq", profile.devId);
		saclient_subscribe(topicStr, 0, on_msgrecv);
		
		/*Send test packet to specific topic*/
		strcpy(pkt.devId, profile.devId);
		strcpy(pkt.handlerName, "Test");
		pkt.requestID = 0;
		pkt.cmd = 0;
		pkt.content = (char*)malloc(strlen("{\"Test\":100}")+1);
		memset(pkt.content, 0, strlen("{\"Test\":100}")+1);
		strcpy(pkt.content, "{\"Test\":100}");
		saclient_publish(topicStr, 0, false, &pkt);
		free(pkt.content);
	}

EXIT:
	printf("Click enter to exit");
	fgetc(stdin);

	/*disconnect from server*/
	saclient_disconnect();
	SUSIAccessAgentLog(Normal, "Send Client Info: disconnect");
	/*release SAClient resource*/
	saclient_uninitialize();
	SUSIAccessAgentLog(Normal, "Agent Uninitialize");
	/*release log resource*/
	UninitLog(SUSIAccessAgentLogHandle);

	return iRet;
}