diff mbox series

Remote Image Handler based on Nanomsg-Next-Generation library

Message ID 20190401141604.14364-1-Wojciech.Michna@assaabloy.com
State Changes Requested
Headers show
Series Remote Image Handler based on Nanomsg-Next-Generation library | expand

Commit Message

Wojciech Michna April 1, 2019, 2:16 p.m. UTC
This is follow up to "Remote Image Handler based on Nanomsg library "

This adds remote handler which uses  NNG library
instead of Zeromq library. This handler works as IPC client
in request-response configuration. It tries to open a connection
to a path defined in the data field and send
an image to the local IPC server.

Signed-off-by: Wojciech Michna <Wojciech.Michna@assaabloy.com>
---
 Kconfig                    |   4 +
 Makefile.deps              |   4 +
 Makefile.flags             |   4 +-
 handlers/Config.in         |  22 +--
 handlers/Makefile          |   2 +-
 handlers/nanomsg_handler.c | 301 -----------------------------------
 handlers/nng_handler.c     | 311 +++++++++++++++++++++++++++++++++++++
 7 files changed, 334 insertions(+), 314 deletions(-)
 delete mode 100644 handlers/nanomsg_handler.c
 create mode 100644 handlers/nng_handler.c

Comments

Stefano Babic April 2, 2019, 6:21 a.m. UTC | #1
Hi Wojciech,

On 01/04/19 16:16, Wojciech Michna wrote:
> This is follow up to "Remote Image Handler based on Nanomsg library "
> 

There could not be a "follow up" patch. Patch V1 was not applied, that
means this patch cannot be applied, too. You should post patches that
can be applied on top of current tree.

Please squash your patches together so that it is possible to review it
and apply it - thanks !

Best regards,
Stefano Babic

> This adds remote handler which uses  NNG library
> instead of Zeromq library. This handler works as IPC client
> in request-response configuration. It tries to open a connection
> to a path defined in the data field and send
> an image to the local IPC server.
> 
> Signed-off-by: Wojciech Michna <Wojciech.Michna@assaabloy.com>
> ---
>  Kconfig                    |   4 +
>  Makefile.deps              |   4 +
>  Makefile.flags             |   4 +-
>  handlers/Config.in         |  22 +--
>  handlers/Makefile          |   2 +-
>  handlers/nanomsg_handler.c | 301 -----------------------------------
>  handlers/nng_handler.c     | 311 +++++++++++++++++++++++++++++++++++++
>  7 files changed, 334 insertions(+), 314 deletions(-)
>  delete mode 100644 handlers/nanomsg_handler.c
>  create mode 100644 handlers/nng_handler.c
> 
> diff --git a/Kconfig b/Kconfig
> index 302166e..0c4d91c 100644
> --- a/Kconfig
> +++ b/Kconfig
> @@ -57,6 +57,10 @@ config HAVE_LIBZEROMQ
>  	bool
>  	option env="HAVE_LIBZEROMQ"
>  
> +config HAVE_LIBNNG
> +	bool
> +	option env="HAVE_LIBNNG"
> +
>  config HAVE_ZLIB
>  	bool
>  	option env="HAVE_ZLIB"
> diff --git a/Makefile.deps b/Makefile.deps
> index e2bf669..573ce70 100644
> --- a/Makefile.deps
> +++ b/Makefile.deps
> @@ -34,6 +34,10 @@ ifeq ($(HAVE_LIBZEROMQ),)
>  export HAVE_LIBZEROMQ = y
>  endif
>  
> +ifeq ($(HAVE_LIBNNG),)
> +export HAVE_LIBNNG = y
> +endif
> +
>  ifeq ($(HAVE_ZLIB),)
>  export HAVE_ZLIB = y
>  endif
> diff --git a/Makefile.flags b/Makefile.flags
> index d991ad3..a544342 100644
> --- a/Makefile.flags
> +++ b/Makefile.flags
> @@ -173,8 +173,8 @@ ifeq ($(CONFIG_REMOTE_HANDLER),y)
>  LDLIBS += zmq
>  endif
>  
> -ifeq ($(CONFIG_NANOMSG_HANDLER),y)
> -LDLIBS += nanomsg
> +ifeq ($(CONFIG_NNG_HANDLER),y)
> +LDLIBS += nng
>  endif
>  
>  ifeq ($(CONFIG_UCFWHANDLER),y)
> diff --git a/handlers/Config.in b/handlers/Config.in
> index cb5816f..a0c880e 100644
> --- a/handlers/Config.in
> +++ b/handlers/Config.in
> @@ -177,19 +177,21 @@ config REMOTE_HANDLER
>  	  the image to be updated with the help of the
>  	  zeromq library.
>  
> -config NANOMSG_HANDLER
> -	bool "nanomsg handler"
> -	default n
> -	help
> -	  Update handler which communicates with external
> -	  processes using NanoMsg communication over
> -	  IPC channel. This handler creates Nanomsg Request
> -	  client which will try to connect to server running
> -	  on a client device. 
> -
>  comment "remote handler needs zeromq"
>  	depends on !HAVE_LIBZEROMQ
>  
> +config NNG_HANDLER
> +	bool "nng handler"
> +	depends on HAVE_LIBNNG
> +	default n
> +	help
> +      This handler forwards image to another listening
> +      process using nng library.
> +	  ("https://nanomsg.github.io/nng/index.html")
> +	  
> +comment "nng handler needs nng library"
> +	depends on !HAVE_LIBNNG
> +
>  config SWUFORWARDER_HANDLER
>  	bool "SWU forwarder"
>  	depends on HAVE_LIBCURL
> diff --git a/handlers/Makefile b/handlers/Makefile
> index 3fad943..66ba4e6 100644
> --- a/handlers/Makefile
> +++ b/handlers/Makefile
> @@ -8,7 +8,7 @@
>  # Handler can be called dynamically based
>  # on the received image type.
>  obj-y	+= dummy_handler.o
> -obj-$(CONFIG_NANOMSG_HANDLER) += nanomsg_handler.o
> +obj-$(CONFIG_NNG_HANDLER) += nng_handler.o
>  obj-$(CONFIG_ARCHIVE) += archive_handler.o
>  obj-$(CONFIG_BOOTLOADERHANDLER) += boot_handler.o
>  obj-$(CONFIG_CFI)	+= flash_handler.o
> diff --git a/handlers/nanomsg_handler.c b/handlers/nanomsg_handler.c
> deleted file mode 100644
> index a06596a..0000000
> --- a/handlers/nanomsg_handler.c
> +++ /dev/null
> @@ -1,301 +0,0 @@
> -/*
> - * (C) Copyright 2019
> - * Wojciech Michna, Assa Aabloy, Wojciech.Michna@assaabloy.com
> - *
> - * SPDX-License-Identifier:     GPL-2.0-or-later
> - */
> -
> -/**
> - * @file nanomsg_handler.c
> - * @brief Handler for remote updates using NanoMsg library
> - * 
> - * 
> - * This file contains update handler which communicates with external
> - * processes using NanoMsg communication over IPC channel.
> - * This handler creates Nanomsg Request client which will try
> - * to connect to server running on a client device. 
> - * 
> - */
> -
> -/* standard includes. */
> -#include <stdio.h>
> -#include <unistd.h>
> -#include <fcntl.h>
> -#include <stdlib.h>
> -#include <errno.h>
> -
> -/* nanomsg specific includes. */
> -#include <nanomsg/nn.h>
> -#include <nanomsg/reqrep.h>
> -
> -/* swupdate specific includes. */
> -#include "swupdate.h"
> -#include "handler.h"
> -#include "util.h"
> -
> -#define ACK_MESSAGE "ACK"
> -#define ACK_MESSAGE_SIZE 3
> -
> -#define RET_SUCCESS 0
> -#define RET_ERROR -1
> -
> -#define LOW_TIMEOUT 1000
> -#define HIGH_TIMEOUT 20000
> -
> -#define EOF_SIZE 1
> -
> -#define MESSAGE_BUFF_SIZE 64
> -char message_buff[MESSAGE_BUFF_SIZE];
> -
> -static void nanomsg_handler(void) __attribute__((constructor));
> -static int send_message_with_ack(int sock, char* message, int n);
> -
> -static unsigned int max_send_size = 0;
> -static int set_max_send_size(int sock);
> -
> -static int send_init(int sock, long long size);
> -static int send_data_begin(int sock);
> -
> -/**
> - * @brief Function sending message and waiting for ACK message
> - * 
> - * @param [in] int sock Socket which will be used to send and receive messages
> - * @param [in] char* message Message which will be send 
> - * @param [in] int n size in bytes of message to send  
> - * 
> - * @return RET_ERROR - indicating send or receive error or RET_SUCCESS - indicating success
> - */
> -static int send_message_with_ack(int sock, char* message, int n){		
> -		int bytes = -1;
> -		int ret = RET_ERROR;
> -		char tmp[ACK_MESSAGE_SIZE];
> -	
> -        if ((bytes = nn_send(sock, message, n, 0)) < 0) {
> -			return ret;
> -        }
> -        
> -        char *buf = NULL;
> -        
> -        /*
> -		 Recieve response from server
> -        */
> -        if ((bytes = nn_recv(sock, &buf, NN_MSG, 0)) <= 0) {
> -			return ret;
> -        }
> -        
> -        /*
> -          Check if we received ACK
> -          Any other message is treated as failure
> -         */
> -		if(bytes >= ACK_MESSAGE_SIZE){
> -			memcpy(tmp,buf,ACK_MESSAGE_SIZE);
> -			if( 0 == strncmp(tmp, ACK_MESSAGE, ACK_MESSAGE_SIZE)){
> -				ret = RET_SUCCESS;
> -			}						
> -		}
> -		
> -        nn_freemsg(buf);
> -		return ret;     
> -}
> -
> -/**
> - * @brief Function sending INIT message
> - * 
> - * @param [in] sock Socket which will be used to send and receive messages
> - * @param [in] long long size Size size of image that will be sent 
> - * 
> - * @return RET_ERROR - indicating send or receive error or RET_SUCCESS - indicating success
> - */
> -static int send_init(int sock, long long size){
> -	snprintf(message_buff, MESSAGE_BUFF_SIZE-EOF_SIZE , "INIT:%lld", size);	
> -	return send_message_with_ack(sock,message_buff,strlen(message_buff));
> -}
> -
> -/**
> - * @brief Function sending DATA message
> - * 
> - * @param [in] sock Socket which will be used to send and receive messages
> - * 
> - * @return RET_ERROR - indicating send or receive error or RET_SUCCESS - indicating success
> - */
> -static int send_data_begin(int sock){
> -	snprintf(message_buff, MESSAGE_BUFF_SIZE-EOF_SIZE , "DATA");
> -	return send_message_with_ack(sock,message_buff,strlen(message_buff));
> -}
> -
> -/**
> - * @brief Function seting maximum size handler is able to send
> - * 
> - * @param [in] sock Socket from which maximum size will be determined
> - * 
> - * @return RET_ERROR - indicating failure when accessing socket RET_SUCCESS - indicating success
> - */
> -static int  set_max_send_size(int sock){
> -	int tmp_send_size;
> -	size_t sz = sizeof (tmp_send_size);
> -	
> -	max_send_size = 0;
> -	
> -	if (nn_getsockopt (sock, NN_SOL_SOCKET, NN_SNDBUF, &tmp_send_size, &sz) < 0) {
> -		return RET_ERROR;
> -	}
> -	
> -	max_send_size = (unsigned int)tmp_send_size;
> -	
> -	return RET_SUCCESS;
> -}
> -
> -/**
> - * @brief Function sending chunks of image data to server
> - * 
> - * @param [in] void *request Pointer to socket, have to be populated before 
> - * @param [in] const void *buf Pointer to buffer containing chunk of data
> - * @param [in] unsigned int len Buffer Length
> - * 
> - * @return EFAULT - indicating failure and interrupt further sending RET_SUCCESS (HAVE TO BE 0) - indicating success
> - */
> -static int forward_data(void *request, const void *buf, unsigned int len)
> -{
> -	int ret = 0;
> -	int* psock = (int*)request;
> -	int sock = 0;
> -	char* tmp = 0x00;
> -	
> -	if ( 0 == psock){
> -		return -EFAULT;
> -	}
> -
> -	sock = *psock;
> -
> -	if(max_send_size<len){
> -		return -EFAULT;
> -	}
> -	
> -	tmp = (char*) malloc(len+EOF_SIZE);
> -	memset(tmp,0x00,len+EOF_SIZE);
> -	memcpy(tmp,buf,len);
> -	ret = send_message_with_ack(sock,tmp,len);
> -	
> -	free(tmp);
> -	
> -	return ret;
> -}
> -
> -/**
> - * @brief Handler installed in swupdate responsible for handling "nanomsg" update type 
> - * 
> - * @param [in] struct img_type *img pointer to update structure 
> - * @param [in] *data unused pointer for compliance with handler definition
> - * 
> - * @return EFAULT - indicating failure and interrupt update RET_SUCCESS (HAVE TO BE 0) - indicating success
> - */
> -static int install_send_to_remote(struct img_type *img,
> -	void __attribute__ ((__unused__)) *data)
> -{	
> -	char *connect_string;
> -	int len;
> -	int sock = 0;
> -	int rv = 0;
> -	int ret = 0;
> -	int time_out = 0;
> -	
> -	if( 0 == img){
> -		ERROR("Critical fault no img passed to handler");
> -		return -EFAULT;
> -	}
> -	
> -	if( 0 == strlen(img->type_data) ){
> -		ERROR("No data section, can't open socket");
> -		return -EFAULT;
> -	}
> -	
> -	len = strlen(img->type_data) 
> -		+ strlen(CONFIG_SOCKET_REMOTE_HANDLER_DIRECTORY)
> -		+ strlen("ipc://")
> -		+ EOF_SIZE;
> -
> -	connect_string = (char*)malloc(len);
> -	
> -	if (!connect_string) {
> -		ERROR("Not enough memory");
> -		return -ENOMEM;
> -	}
> -	
> -	snprintf(	connect_string,
> -				len,
> -				"ipc://%s%s",
> -				CONFIG_SOCKET_REMOTE_HANDLER_DIRECTORY,
> -				img->type_data);
> -	
> -	if (( sock = nn_socket(AF_SP, NN_REQ)) < 0) {
> -		ERROR("Can't create socket");
> -		free(connect_string);
> -		return -EFAULT;
> -	}
> -		
> -	if (( rv = nn_connect (sock, connect_string)) < 0) {
> -		ERROR("Can't connect to socket");
> -		free(connect_string);
> -		return -EFAULT;
> -	}
> -	
> -	time_out = LOW_TIMEOUT;
> -	if (nn_setsockopt(sock, NN_SOL_SOCKET, NN_RCVTIMEO, &time_out, sizeof (time_out)) < 0) {
> -		ERROR("Can't change opt");
> -		nn_shutdown(sock, rv);
> -		free(connect_string);
> -		return -EFAULT;
> -	}
> -
> -	if(send_init(sock, img->size ) != 0){
> -		ERROR("Sending init message failed");
> -		nn_shutdown(sock, rv);
> -		free(connect_string);
> -		return -EFAULT;
> -	}
> -	
> -	if(send_data_begin(sock) != 0){
> -		ERROR("Sending data message failed");
> -		nn_shutdown(sock, rv);
> -		free(connect_string);
> -		return -EFAULT;
> -	}
> -	
> -	time_out = HIGH_TIMEOUT;
> -	if (nn_setsockopt(sock, NN_SOL_SOCKET, NN_RCVTIMEO, &time_out, sizeof (time_out)) < 0) {
> -		ERROR("Can't change opt");
> -		nn_shutdown(sock, rv);
> -		free(connect_string);
> -		return -EFAULT;
> -	}
> -	
> -	if (set_max_send_size(sock) != RET_SUCCESS) {
> -		ERROR("Can't set max send size");
> -		nn_shutdown(sock, rv);
> -		free(connect_string);
> -		return -EFAULT;
> -	}
> -	
> -	ret = copyimage(&sock, img, forward_data);	
> -		
> -	nn_shutdown(sock, rv);
> -	free(connect_string);
> -	
> -	if(ret != 0){
> -		ERROR("Send error");
> -		return -EFAULT;
> -	}
> -	
> -	return RET_SUCCESS;
> -}
> -
> -/**
> - * @brief Constructor function run at start of application responsible for installing handler
> - */
> -static void nanomsg_handler(void)
> -{
> -	register_handler("nanomsg",
> -					 install_send_to_remote,
> -					 IMAGE_HANDLER,
> -					 NULL);
> -}
> diff --git a/handlers/nng_handler.c b/handlers/nng_handler.c
> new file mode 100644
> index 0000000..81cba24
> --- /dev/null
> +++ b/handlers/nng_handler.c
> @@ -0,0 +1,311 @@
> +/*
> + * nng_handler.c: Remote handler which allows passing an image to another process
> + * (C) Copyright 2019
> + * Wojciech Michna, Assa Aabloy, Wojciech.Michna@assaabloy.com
> + *
> + * SPDX-License-Identifier:     GPL-2.0-or-later
> + */
> +
> +/**
> + * @file nng_handler.c
> + * @brief Handler for remote updates using NanoMsg library
> + *
> + *
> + * This file contains update handler which communicates with external
> + * processes using NanoMsg communication over IPC channel.
> + * This handler creates NNG Request client which will try
> + * to connect to server running on a client device.
> + *
> + */
> +
> +#include <stdio.h>
> +#include <unistd.h>
> +#include <fcntl.h>
> +#include <stdlib.h>
> +#include <errno.h>
> +
> +#include <nng/nng.h>
> +#include <nng/protocol/reqrep0/req.h>
> +
> +#include "swupdate.h"
> +#include "handler.h"
> +#include "util.h"
> +
> +#define ACK_MESSAGE "ACK"
> +#define ACK_MESSAGE_SIZE 3
> +
> +#define DEFAULT_MESSAGE_TIMEOUT 1000
> +#define DEFAULT_DATA_TIMEOUT 20000
> +
> +#define message_timeout_key "message-timeout"
> +#define data_timeout_key "data-timeout"
> +
> +#define NULL_CHAR_SIZE 1
> +
> +static void nng_handler(void) __attribute__((constructor));
> +static int send_message_with_ack(nng_socket sock, char *message, int n);
> +
> +static int send_init(nng_socket sock, long long size);
> +static void parse_image_properties(struct dict *dictionary);
> +
> +static int message_timeout = DEFAULT_MESSAGE_TIMEOUT;
> +static int data_timeout = DEFAULT_DATA_TIMEOUT;
> +
> +/**
> + * @brief Function sending message and waiting for ACK message
> + *
> + * @param [in] int sock Socket which will be used to send and receive messages
> + * @param [in] char* message Message which will be send
> + * @param [in] int n size in bytes of message to send
> + *
> + * @return Error Code - indicating send or receive error or 0 - when success
> + */
> +static int send_message_with_ack(nng_socket sock, char *message, int n)
> +{
> +	int ret = -ECOMM;
> +	char tmp[ACK_MESSAGE_SIZE];
> +	char *buf = NULL;
> +	size_t sz = 0;
> +	int rv = NNG_ECONNREFUSED;
> +
> +	rv = nng_send(sock, message, n, 0);
> +	if (rv) {
> +		return rv;
> +	}
> +	/*
> +	 * Recieve response from server
> +	 */
> +	rv = nng_recv(sock, &buf, &sz, NNG_FLAG_ALLOC);
> +	if (rv) {
> +		return rv;
> +	}
> +
> +	/*
> +	 * Check if we received ACK
> +	 * Any other message is treated as failure
> +	 */
> +	if (sz >= ACK_MESSAGE_SIZE) {
> +		memcpy(tmp, buf, ACK_MESSAGE_SIZE);
> +		if (strncmp(tmp, ACK_MESSAGE, ACK_MESSAGE_SIZE) == 0) {
> +			ret = 0;
> +		}
> +	}
> +
> +	nng_free(buf, sz);
> +	return ret;
> +}
> +
> +/**
> + * @brief Function sending INIT message
> + *
> + * @param [in] sock Socket which will be used to send and receive messages
> + * @param [in] long long size Size size of image that will be sent
> + *
> + * @return Error Code - indicating send error or 0 - indicating success
> + */
> +static int send_init(nng_socket sock, long long size)
> +{
> +	// long long max is 4294967295 - 10 chars we add 11 for null terminator
> +	int str_len = strlen("INIT:") + 10 + NULL_CHAR_SIZE;
> +	char *message_buff = NULL;
> +	int rv = NNG_ECONNREFUSED;
> +
> +	if (!size) {
> +		return rv;
> +	}
> +
> +	message_buff = (char *)malloc(str_len);
> +
> +	if (message_buff == NULL) {
> +		return NNG_ENOMEM;
> +	}
> +
> +	snprintf(message_buff, str_len, "INIT:%lld", size);
> +	rv = send_message_with_ack(sock, message_buff, strlen(message_buff));
> +	free(message_buff);
> +	return rv;
> +}
> +
> +/**
> + * @brief Function sending chunks of image data to server
> + *
> + * @param [in] void *request Pointer to socket, have to be populated before
> + * @param [in] const void *buf Pointer to buffer containing chunk of data
> + * @param [in] unsigned int len Buffer Length
> + *
> + * @return EFAULT - indicating failure and interrupt further sending
> + *		0 - indicating success
> + */
> +static int forward_data(void *request, const void *buf, unsigned int len)
> +{
> +	int ret = 0;
> +	nng_socket *psock = (nng_socket *)request;
> +	char *tmp = NULL;
> +
> +	if (psock == NULL || nng_socket_id(*psock) < 0) {
> +		return -EFAULT;
> +	}
> +
> +	if (!len) {
> +		return -EFAULT;
> +	}
> +
> +	tmp = (char *)malloc(len + NULL_CHAR_SIZE);
> +
> +	if (tmp == NULL) {
> +		return -ENOMEM;
> +	}
> +
> +	memcpy(tmp, buf, len);
> +	ret = send_message_with_ack(*psock, tmp, len);
> +
> +	free(tmp);
> +	return ret;
> +}
> +
> +/**
> + * @brief Parse dictionary with properties from sw-description
> + *
> + * This function parses image properties contained in sw-description
> + * Example: properties = {message-timeout = "1000";data-timeout = "5000";};
> + *
> + * @param [in] struct dict *dictionary Pointer to properties dictionary
> + *		From image structure
> + */
> +static void parse_image_properties(struct dict *dictionary)
> +{
> +	char *str = NULL;
> +
> +	if (dictionary == NULL) {
> +		return;
> +	}
> +
> +	str = dict_get_value(dictionary, message_timeout_key);
> +	if (str != NULL) {
> +		message_timeout = atoi(str);
> +	}
> +	str = dict_get_value(dictionary, data_timeout_key);
> +	if (str != NULL) {
> +		data_timeout = atoi(str);
> +	}
> +}
> +
> +/**
> + * @brief Handler installed in swupdate responsible for handling "nng" update type
> + *
> + * @param [in] struct img_type *img pointer to update structure
> + * @param [in] *data unused pointer for compliance with handler definition
> + *
> + * @return EFAULT - indicating failure and interrupt update RET_SUCCESS (HAVE TO BE 0) - indicating success
> + */
> +static int install_send_to_remote(struct img_type *img,
> +		void __attribute__ ((__unused__)) *data)
> +{
> +	char *connect_string = NULL;
> +	int len = 0;
> +	nng_socket sock;
> +	int rv = 0;
> +	int ret = 0;
> +	int time_out = 0;
> +
> +	if (!img) {
> +		ERROR("Critical fault no img passed to handler");
> +		return -EFAULT;
> +	}
> +
> +	if (!strlen(img->type_data)) {
> +		ERROR("No data section, can't open socket");
> +		return -EFAULT;
> +	}
> +
> +	parse_image_properties(&img->properties);
> +
> +	len = strlen(img->type_data)
> +			+ strlen(CONFIG_SOCKET_REMOTE_HANDLER_DIRECTORY)
> +			+ strlen("ipc://")
> +			+ NULL_CHAR_SIZE;
> +
> +	connect_string = (char *)malloc(len);
> +
> +	if (!connect_string) {
> +		ERROR("Not enough memory");
> +		return -ENOMEM;
> +	}
> +
> +	snprintf(connect_string,
> +			len,
> +			"ipc://%s%s",
> +			CONFIG_SOCKET_REMOTE_HANDLER_DIRECTORY,
> +			img->type_data);
> +
> +	rv = nng_req0_open(&sock);
> +	if (rv) {
> +		ERROR("Can't create socket, NNG internal error:%s", nng_strerror(rv));
> +		free(connect_string);
> +		return -EFAULT;
> +	}
> +
> +	rv = nng_dial(sock, connect_string, NULL, 0);
> +	if (rv) {
> +		ERROR("Can't connect to socket, NNG internal error:%s", nng_strerror(rv));
> +		free(connect_string);
> +		return -EFAULT;
> +	}
> +
> +	time_out = message_timeout;
> +	rv = nng_setopt(sock, NNG_OPT_RECVTIMEO, &time_out, sizeof(time_out));
> +	if (rv) {
> +		ERROR("Can't change opt, NNG internal error:%s", nng_strerror(rv));
> +		nng_close(sock);
> +		free(connect_string);
> +		return -EFAULT;
> +	}
> +
> +	rv = send_init(sock, img->size);
> +	if (rv) {
> +		ERROR("Sending init message failed, NNG internal error:%s", nng_strerror(rv));
> +		nng_close(sock);
> +		free(connect_string);
> +		return -EFAULT;
> +	}
> +
> +	rv = send_message_with_ack(sock, (char *)"DATA", strlen("DATA"));
> +	if (rv) {
> +		ERROR("Sending data message failed, NNG internal error:%s", nng_strerror(rv));
> +		nng_close(sock);
> +		free(connect_string);
> +		return -EFAULT;
> +	}
> +
> +	time_out = data_timeout;
> +	rv = nng_setopt(sock, NNG_OPT_RECVTIMEO, &time_out, sizeof(time_out));
> +	if (rv) {
> +		ERROR("Can't change opt, NNG internal error:%s", nng_strerror(rv));
> +		nng_close(sock);
> +		free(connect_string);
> +		return -EFAULT;
> +	}
> +
> +	ret = copyimage(&sock, img, forward_data);
> +
> +	nng_close(sock);
> +	free(connect_string);
> +
> +	if (ret) {
> +		ERROR("Send error");
> +		return -EFAULT;
> +	}
> +
> +	return 0;
> +}
> +
> +/**
> + * @brief Constructor function run at start of application responsible for installing handler
> + */
> +static void nng_handler(void)
> +{
> +	register_handler("nng",
> +			install_send_to_remote,
> +			IMAGE_HANDLER,
> +			NULL);
> +}
> 

Best regards,
Stefano Babic
diff mbox series

Patch

diff --git a/Kconfig b/Kconfig
index 302166e..0c4d91c 100644
--- a/Kconfig
+++ b/Kconfig
@@ -57,6 +57,10 @@  config HAVE_LIBZEROMQ
 	bool
 	option env="HAVE_LIBZEROMQ"
 
+config HAVE_LIBNNG
+	bool
+	option env="HAVE_LIBNNG"
+
 config HAVE_ZLIB
 	bool
 	option env="HAVE_ZLIB"
diff --git a/Makefile.deps b/Makefile.deps
index e2bf669..573ce70 100644
--- a/Makefile.deps
+++ b/Makefile.deps
@@ -34,6 +34,10 @@  ifeq ($(HAVE_LIBZEROMQ),)
 export HAVE_LIBZEROMQ = y
 endif
 
+ifeq ($(HAVE_LIBNNG),)
+export HAVE_LIBNNG = y
+endif
+
 ifeq ($(HAVE_ZLIB),)
 export HAVE_ZLIB = y
 endif
diff --git a/Makefile.flags b/Makefile.flags
index d991ad3..a544342 100644
--- a/Makefile.flags
+++ b/Makefile.flags
@@ -173,8 +173,8 @@  ifeq ($(CONFIG_REMOTE_HANDLER),y)
 LDLIBS += zmq
 endif
 
-ifeq ($(CONFIG_NANOMSG_HANDLER),y)
-LDLIBS += nanomsg
+ifeq ($(CONFIG_NNG_HANDLER),y)
+LDLIBS += nng
 endif
 
 ifeq ($(CONFIG_UCFWHANDLER),y)
diff --git a/handlers/Config.in b/handlers/Config.in
index cb5816f..a0c880e 100644
--- a/handlers/Config.in
+++ b/handlers/Config.in
@@ -177,19 +177,21 @@  config REMOTE_HANDLER
 	  the image to be updated with the help of the
 	  zeromq library.
 
-config NANOMSG_HANDLER
-	bool "nanomsg handler"
-	default n
-	help
-	  Update handler which communicates with external
-	  processes using NanoMsg communication over
-	  IPC channel. This handler creates Nanomsg Request
-	  client which will try to connect to server running
-	  on a client device. 
-
 comment "remote handler needs zeromq"
 	depends on !HAVE_LIBZEROMQ
 
+config NNG_HANDLER
+	bool "nng handler"
+	depends on HAVE_LIBNNG
+	default n
+	help
+      This handler forwards image to another listening
+      process using nng library.
+	  ("https://nanomsg.github.io/nng/index.html")
+	  
+comment "nng handler needs nng library"
+	depends on !HAVE_LIBNNG
+
 config SWUFORWARDER_HANDLER
 	bool "SWU forwarder"
 	depends on HAVE_LIBCURL
diff --git a/handlers/Makefile b/handlers/Makefile
index 3fad943..66ba4e6 100644
--- a/handlers/Makefile
+++ b/handlers/Makefile
@@ -8,7 +8,7 @@ 
 # Handler can be called dynamically based
 # on the received image type.
 obj-y	+= dummy_handler.o
-obj-$(CONFIG_NANOMSG_HANDLER) += nanomsg_handler.o
+obj-$(CONFIG_NNG_HANDLER) += nng_handler.o
 obj-$(CONFIG_ARCHIVE) += archive_handler.o
 obj-$(CONFIG_BOOTLOADERHANDLER) += boot_handler.o
 obj-$(CONFIG_CFI)	+= flash_handler.o
diff --git a/handlers/nanomsg_handler.c b/handlers/nanomsg_handler.c
deleted file mode 100644
index a06596a..0000000
--- a/handlers/nanomsg_handler.c
+++ /dev/null
@@ -1,301 +0,0 @@ 
-/*
- * (C) Copyright 2019
- * Wojciech Michna, Assa Aabloy, Wojciech.Michna@assaabloy.com
- *
- * SPDX-License-Identifier:     GPL-2.0-or-later
- */
-
-/**
- * @file nanomsg_handler.c
- * @brief Handler for remote updates using NanoMsg library
- * 
- * 
- * This file contains update handler which communicates with external
- * processes using NanoMsg communication over IPC channel.
- * This handler creates Nanomsg Request client which will try
- * to connect to server running on a client device. 
- * 
- */
-
-/* standard includes. */
-#include <stdio.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <stdlib.h>
-#include <errno.h>
-
-/* nanomsg specific includes. */
-#include <nanomsg/nn.h>
-#include <nanomsg/reqrep.h>
-
-/* swupdate specific includes. */
-#include "swupdate.h"
-#include "handler.h"
-#include "util.h"
-
-#define ACK_MESSAGE "ACK"
-#define ACK_MESSAGE_SIZE 3
-
-#define RET_SUCCESS 0
-#define RET_ERROR -1
-
-#define LOW_TIMEOUT 1000
-#define HIGH_TIMEOUT 20000
-
-#define EOF_SIZE 1
-
-#define MESSAGE_BUFF_SIZE 64
-char message_buff[MESSAGE_BUFF_SIZE];
-
-static void nanomsg_handler(void) __attribute__((constructor));
-static int send_message_with_ack(int sock, char* message, int n);
-
-static unsigned int max_send_size = 0;
-static int set_max_send_size(int sock);
-
-static int send_init(int sock, long long size);
-static int send_data_begin(int sock);
-
-/**
- * @brief Function sending message and waiting for ACK message
- * 
- * @param [in] int sock Socket which will be used to send and receive messages
- * @param [in] char* message Message which will be send 
- * @param [in] int n size in bytes of message to send  
- * 
- * @return RET_ERROR - indicating send or receive error or RET_SUCCESS - indicating success
- */
-static int send_message_with_ack(int sock, char* message, int n){		
-		int bytes = -1;
-		int ret = RET_ERROR;
-		char tmp[ACK_MESSAGE_SIZE];
-	
-        if ((bytes = nn_send(sock, message, n, 0)) < 0) {
-			return ret;
-        }
-        
-        char *buf = NULL;
-        
-        /*
-		 Recieve response from server
-        */
-        if ((bytes = nn_recv(sock, &buf, NN_MSG, 0)) <= 0) {
-			return ret;
-        }
-        
-        /*
-          Check if we received ACK
-          Any other message is treated as failure
-         */
-		if(bytes >= ACK_MESSAGE_SIZE){
-			memcpy(tmp,buf,ACK_MESSAGE_SIZE);
-			if( 0 == strncmp(tmp, ACK_MESSAGE, ACK_MESSAGE_SIZE)){
-				ret = RET_SUCCESS;
-			}						
-		}
-		
-        nn_freemsg(buf);
-		return ret;     
-}
-
-/**
- * @brief Function sending INIT message
- * 
- * @param [in] sock Socket which will be used to send and receive messages
- * @param [in] long long size Size size of image that will be sent 
- * 
- * @return RET_ERROR - indicating send or receive error or RET_SUCCESS - indicating success
- */
-static int send_init(int sock, long long size){
-	snprintf(message_buff, MESSAGE_BUFF_SIZE-EOF_SIZE , "INIT:%lld", size);	
-	return send_message_with_ack(sock,message_buff,strlen(message_buff));
-}
-
-/**
- * @brief Function sending DATA message
- * 
- * @param [in] sock Socket which will be used to send and receive messages
- * 
- * @return RET_ERROR - indicating send or receive error or RET_SUCCESS - indicating success
- */
-static int send_data_begin(int sock){
-	snprintf(message_buff, MESSAGE_BUFF_SIZE-EOF_SIZE , "DATA");
-	return send_message_with_ack(sock,message_buff,strlen(message_buff));
-}
-
-/**
- * @brief Function seting maximum size handler is able to send
- * 
- * @param [in] sock Socket from which maximum size will be determined
- * 
- * @return RET_ERROR - indicating failure when accessing socket RET_SUCCESS - indicating success
- */
-static int  set_max_send_size(int sock){
-	int tmp_send_size;
-	size_t sz = sizeof (tmp_send_size);
-	
-	max_send_size = 0;
-	
-	if (nn_getsockopt (sock, NN_SOL_SOCKET, NN_SNDBUF, &tmp_send_size, &sz) < 0) {
-		return RET_ERROR;
-	}
-	
-	max_send_size = (unsigned int)tmp_send_size;
-	
-	return RET_SUCCESS;
-}
-
-/**
- * @brief Function sending chunks of image data to server
- * 
- * @param [in] void *request Pointer to socket, have to be populated before 
- * @param [in] const void *buf Pointer to buffer containing chunk of data
- * @param [in] unsigned int len Buffer Length
- * 
- * @return EFAULT - indicating failure and interrupt further sending RET_SUCCESS (HAVE TO BE 0) - indicating success
- */
-static int forward_data(void *request, const void *buf, unsigned int len)
-{
-	int ret = 0;
-	int* psock = (int*)request;
-	int sock = 0;
-	char* tmp = 0x00;
-	
-	if ( 0 == psock){
-		return -EFAULT;
-	}
-
-	sock = *psock;
-
-	if(max_send_size<len){
-		return -EFAULT;
-	}
-	
-	tmp = (char*) malloc(len+EOF_SIZE);
-	memset(tmp,0x00,len+EOF_SIZE);
-	memcpy(tmp,buf,len);
-	ret = send_message_with_ack(sock,tmp,len);
-	
-	free(tmp);
-	
-	return ret;
-}
-
-/**
- * @brief Handler installed in swupdate responsible for handling "nanomsg" update type 
- * 
- * @param [in] struct img_type *img pointer to update structure 
- * @param [in] *data unused pointer for compliance with handler definition
- * 
- * @return EFAULT - indicating failure and interrupt update RET_SUCCESS (HAVE TO BE 0) - indicating success
- */
-static int install_send_to_remote(struct img_type *img,
-	void __attribute__ ((__unused__)) *data)
-{	
-	char *connect_string;
-	int len;
-	int sock = 0;
-	int rv = 0;
-	int ret = 0;
-	int time_out = 0;
-	
-	if( 0 == img){
-		ERROR("Critical fault no img passed to handler");
-		return -EFAULT;
-	}
-	
-	if( 0 == strlen(img->type_data) ){
-		ERROR("No data section, can't open socket");
-		return -EFAULT;
-	}
-	
-	len = strlen(img->type_data) 
-		+ strlen(CONFIG_SOCKET_REMOTE_HANDLER_DIRECTORY)
-		+ strlen("ipc://")
-		+ EOF_SIZE;
-
-	connect_string = (char*)malloc(len);
-	
-	if (!connect_string) {
-		ERROR("Not enough memory");
-		return -ENOMEM;
-	}
-	
-	snprintf(	connect_string,
-				len,
-				"ipc://%s%s",
-				CONFIG_SOCKET_REMOTE_HANDLER_DIRECTORY,
-				img->type_data);
-	
-	if (( sock = nn_socket(AF_SP, NN_REQ)) < 0) {
-		ERROR("Can't create socket");
-		free(connect_string);
-		return -EFAULT;
-	}
-		
-	if (( rv = nn_connect (sock, connect_string)) < 0) {
-		ERROR("Can't connect to socket");
-		free(connect_string);
-		return -EFAULT;
-	}
-	
-	time_out = LOW_TIMEOUT;
-	if (nn_setsockopt(sock, NN_SOL_SOCKET, NN_RCVTIMEO, &time_out, sizeof (time_out)) < 0) {
-		ERROR("Can't change opt");
-		nn_shutdown(sock, rv);
-		free(connect_string);
-		return -EFAULT;
-	}
-
-	if(send_init(sock, img->size ) != 0){
-		ERROR("Sending init message failed");
-		nn_shutdown(sock, rv);
-		free(connect_string);
-		return -EFAULT;
-	}
-	
-	if(send_data_begin(sock) != 0){
-		ERROR("Sending data message failed");
-		nn_shutdown(sock, rv);
-		free(connect_string);
-		return -EFAULT;
-	}
-	
-	time_out = HIGH_TIMEOUT;
-	if (nn_setsockopt(sock, NN_SOL_SOCKET, NN_RCVTIMEO, &time_out, sizeof (time_out)) < 0) {
-		ERROR("Can't change opt");
-		nn_shutdown(sock, rv);
-		free(connect_string);
-		return -EFAULT;
-	}
-	
-	if (set_max_send_size(sock) != RET_SUCCESS) {
-		ERROR("Can't set max send size");
-		nn_shutdown(sock, rv);
-		free(connect_string);
-		return -EFAULT;
-	}
-	
-	ret = copyimage(&sock, img, forward_data);	
-		
-	nn_shutdown(sock, rv);
-	free(connect_string);
-	
-	if(ret != 0){
-		ERROR("Send error");
-		return -EFAULT;
-	}
-	
-	return RET_SUCCESS;
-}
-
-/**
- * @brief Constructor function run at start of application responsible for installing handler
- */
-static void nanomsg_handler(void)
-{
-	register_handler("nanomsg",
-					 install_send_to_remote,
-					 IMAGE_HANDLER,
-					 NULL);
-}
diff --git a/handlers/nng_handler.c b/handlers/nng_handler.c
new file mode 100644
index 0000000..81cba24
--- /dev/null
+++ b/handlers/nng_handler.c
@@ -0,0 +1,311 @@ 
+/*
+ * nng_handler.c: Remote handler which allows passing an image to another process
+ * (C) Copyright 2019
+ * Wojciech Michna, Assa Aabloy, Wojciech.Michna@assaabloy.com
+ *
+ * SPDX-License-Identifier:     GPL-2.0-or-later
+ */
+
+/**
+ * @file nng_handler.c
+ * @brief Handler for remote updates using NanoMsg library
+ *
+ *
+ * This file contains update handler which communicates with external
+ * processes using NanoMsg communication over IPC channel.
+ * This handler creates NNG Request client which will try
+ * to connect to server running on a client device.
+ *
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include <nng/nng.h>
+#include <nng/protocol/reqrep0/req.h>
+
+#include "swupdate.h"
+#include "handler.h"
+#include "util.h"
+
+#define ACK_MESSAGE "ACK"
+#define ACK_MESSAGE_SIZE 3
+
+#define DEFAULT_MESSAGE_TIMEOUT 1000
+#define DEFAULT_DATA_TIMEOUT 20000
+
+#define message_timeout_key "message-timeout"
+#define data_timeout_key "data-timeout"
+
+#define NULL_CHAR_SIZE 1
+
+static void nng_handler(void) __attribute__((constructor));
+static int send_message_with_ack(nng_socket sock, char *message, int n);
+
+static int send_init(nng_socket sock, long long size);
+static void parse_image_properties(struct dict *dictionary);
+
+static int message_timeout = DEFAULT_MESSAGE_TIMEOUT;
+static int data_timeout = DEFAULT_DATA_TIMEOUT;
+
+/**
+ * @brief Function sending message and waiting for ACK message
+ *
+ * @param [in] int sock Socket which will be used to send and receive messages
+ * @param [in] char* message Message which will be send
+ * @param [in] int n size in bytes of message to send
+ *
+ * @return Error Code - indicating send or receive error or 0 - when success
+ */
+static int send_message_with_ack(nng_socket sock, char *message, int n)
+{
+	int ret = -ECOMM;
+	char tmp[ACK_MESSAGE_SIZE];
+	char *buf = NULL;
+	size_t sz = 0;
+	int rv = NNG_ECONNREFUSED;
+
+	rv = nng_send(sock, message, n, 0);
+	if (rv) {
+		return rv;
+	}
+	/*
+	 * Recieve response from server
+	 */
+	rv = nng_recv(sock, &buf, &sz, NNG_FLAG_ALLOC);
+	if (rv) {
+		return rv;
+	}
+
+	/*
+	 * Check if we received ACK
+	 * Any other message is treated as failure
+	 */
+	if (sz >= ACK_MESSAGE_SIZE) {
+		memcpy(tmp, buf, ACK_MESSAGE_SIZE);
+		if (strncmp(tmp, ACK_MESSAGE, ACK_MESSAGE_SIZE) == 0) {
+			ret = 0;
+		}
+	}
+
+	nng_free(buf, sz);
+	return ret;
+}
+
+/**
+ * @brief Function sending INIT message
+ *
+ * @param [in] sock Socket which will be used to send and receive messages
+ * @param [in] long long size Size size of image that will be sent
+ *
+ * @return Error Code - indicating send error or 0 - indicating success
+ */
+static int send_init(nng_socket sock, long long size)
+{
+	// long long max is 4294967295 - 10 chars we add 11 for null terminator
+	int str_len = strlen("INIT:") + 10 + NULL_CHAR_SIZE;
+	char *message_buff = NULL;
+	int rv = NNG_ECONNREFUSED;
+
+	if (!size) {
+		return rv;
+	}
+
+	message_buff = (char *)malloc(str_len);
+
+	if (message_buff == NULL) {
+		return NNG_ENOMEM;
+	}
+
+	snprintf(message_buff, str_len, "INIT:%lld", size);
+	rv = send_message_with_ack(sock, message_buff, strlen(message_buff));
+	free(message_buff);
+	return rv;
+}
+
+/**
+ * @brief Function sending chunks of image data to server
+ *
+ * @param [in] void *request Pointer to socket, have to be populated before
+ * @param [in] const void *buf Pointer to buffer containing chunk of data
+ * @param [in] unsigned int len Buffer Length
+ *
+ * @return EFAULT - indicating failure and interrupt further sending
+ *		0 - indicating success
+ */
+static int forward_data(void *request, const void *buf, unsigned int len)
+{
+	int ret = 0;
+	nng_socket *psock = (nng_socket *)request;
+	char *tmp = NULL;
+
+	if (psock == NULL || nng_socket_id(*psock) < 0) {
+		return -EFAULT;
+	}
+
+	if (!len) {
+		return -EFAULT;
+	}
+
+	tmp = (char *)malloc(len + NULL_CHAR_SIZE);
+
+	if (tmp == NULL) {
+		return -ENOMEM;
+	}
+
+	memcpy(tmp, buf, len);
+	ret = send_message_with_ack(*psock, tmp, len);
+
+	free(tmp);
+	return ret;
+}
+
+/**
+ * @brief Parse dictionary with properties from sw-description
+ *
+ * This function parses image properties contained in sw-description
+ * Example: properties = {message-timeout = "1000";data-timeout = "5000";};
+ *
+ * @param [in] struct dict *dictionary Pointer to properties dictionary
+ *		From image structure
+ */
+static void parse_image_properties(struct dict *dictionary)
+{
+	char *str = NULL;
+
+	if (dictionary == NULL) {
+		return;
+	}
+
+	str = dict_get_value(dictionary, message_timeout_key);
+	if (str != NULL) {
+		message_timeout = atoi(str);
+	}
+	str = dict_get_value(dictionary, data_timeout_key);
+	if (str != NULL) {
+		data_timeout = atoi(str);
+	}
+}
+
+/**
+ * @brief Handler installed in swupdate responsible for handling "nng" update type
+ *
+ * @param [in] struct img_type *img pointer to update structure
+ * @param [in] *data unused pointer for compliance with handler definition
+ *
+ * @return EFAULT - indicating failure and interrupt update RET_SUCCESS (HAVE TO BE 0) - indicating success
+ */
+static int install_send_to_remote(struct img_type *img,
+		void __attribute__ ((__unused__)) *data)
+{
+	char *connect_string = NULL;
+	int len = 0;
+	nng_socket sock;
+	int rv = 0;
+	int ret = 0;
+	int time_out = 0;
+
+	if (!img) {
+		ERROR("Critical fault no img passed to handler");
+		return -EFAULT;
+	}
+
+	if (!strlen(img->type_data)) {
+		ERROR("No data section, can't open socket");
+		return -EFAULT;
+	}
+
+	parse_image_properties(&img->properties);
+
+	len = strlen(img->type_data)
+			+ strlen(CONFIG_SOCKET_REMOTE_HANDLER_DIRECTORY)
+			+ strlen("ipc://")
+			+ NULL_CHAR_SIZE;
+
+	connect_string = (char *)malloc(len);
+
+	if (!connect_string) {
+		ERROR("Not enough memory");
+		return -ENOMEM;
+	}
+
+	snprintf(connect_string,
+			len,
+			"ipc://%s%s",
+			CONFIG_SOCKET_REMOTE_HANDLER_DIRECTORY,
+			img->type_data);
+
+	rv = nng_req0_open(&sock);
+	if (rv) {
+		ERROR("Can't create socket, NNG internal error:%s", nng_strerror(rv));
+		free(connect_string);
+		return -EFAULT;
+	}
+
+	rv = nng_dial(sock, connect_string, NULL, 0);
+	if (rv) {
+		ERROR("Can't connect to socket, NNG internal error:%s", nng_strerror(rv));
+		free(connect_string);
+		return -EFAULT;
+	}
+
+	time_out = message_timeout;
+	rv = nng_setopt(sock, NNG_OPT_RECVTIMEO, &time_out, sizeof(time_out));
+	if (rv) {
+		ERROR("Can't change opt, NNG internal error:%s", nng_strerror(rv));
+		nng_close(sock);
+		free(connect_string);
+		return -EFAULT;
+	}
+
+	rv = send_init(sock, img->size);
+	if (rv) {
+		ERROR("Sending init message failed, NNG internal error:%s", nng_strerror(rv));
+		nng_close(sock);
+		free(connect_string);
+		return -EFAULT;
+	}
+
+	rv = send_message_with_ack(sock, (char *)"DATA", strlen("DATA"));
+	if (rv) {
+		ERROR("Sending data message failed, NNG internal error:%s", nng_strerror(rv));
+		nng_close(sock);
+		free(connect_string);
+		return -EFAULT;
+	}
+
+	time_out = data_timeout;
+	rv = nng_setopt(sock, NNG_OPT_RECVTIMEO, &time_out, sizeof(time_out));
+	if (rv) {
+		ERROR("Can't change opt, NNG internal error:%s", nng_strerror(rv));
+		nng_close(sock);
+		free(connect_string);
+		return -EFAULT;
+	}
+
+	ret = copyimage(&sock, img, forward_data);
+
+	nng_close(sock);
+	free(connect_string);
+
+	if (ret) {
+		ERROR("Send error");
+		return -EFAULT;
+	}
+
+	return 0;
+}
+
+/**
+ * @brief Constructor function run at start of application responsible for installing handler
+ */
+static void nng_handler(void)
+{
+	register_handler("nng",
+			install_send_to_remote,
+			IMAGE_HANDLER,
+			NULL);
+}