915 lines
24 KiB
C
915 lines
24 KiB
C
/*
|
|
*
|
|
Copyright (C) 2009-2016 Olof Hagsand and Benny Holmgren
|
|
|
|
This file is part of CLIXON.
|
|
|
|
CLIXON is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
CLIXON is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with CLIXON; see the file LICENSE. If not, see
|
|
<http://www.gnu.org/licenses/>.
|
|
|
|
*
|
|
* Protocol to communicate between clients (eg clicon_cli, clicon_netconf)
|
|
* and server (clicon_backend)
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "clixon_config.h" /* generated by config & autoconf */
|
|
#endif
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <stdarg.h>
|
|
#include <fcntl.h>
|
|
#include <unistd.h>
|
|
#include <errno.h>
|
|
#include <string.h>
|
|
#include <assert.h>
|
|
#include <syslog.h>
|
|
#include <signal.h>
|
|
#include <ctype.h>
|
|
#include <sys/types.h>
|
|
#include <sys/time.h>
|
|
#include <sys/socket.h>
|
|
#include <netinet/in.h>
|
|
#include <arpa/inet.h>
|
|
|
|
/* cligen */
|
|
#include <cligen/cligen.h>
|
|
|
|
/* clicon */
|
|
#include "clixon_err.h"
|
|
#include "clixon_log.h"
|
|
#include "clixon_queue.h"
|
|
#include "clixon_chunk.h"
|
|
#include "clixon_sig.h"
|
|
#include "clixon_hash.h"
|
|
#include "clixon_handle.h"
|
|
#include "clixon_proto.h"
|
|
#include "clixon_proto_encode.h"
|
|
|
|
struct clicon_msg *
|
|
clicon_msg_commit_encode(char *dbsrc, char *dbdst,
|
|
uint32_t snapshot, uint32_t startup,
|
|
const char *label)
|
|
{
|
|
struct clicon_msg *msg;
|
|
uint16_t len;
|
|
int hdrlen = sizeof(*msg);
|
|
int p;
|
|
uint32_t tmp;
|
|
|
|
clicon_debug(2, "%s: snapshot: %d startup: %d dbsrc: %s dbdst: %s",
|
|
__FUNCTION__,
|
|
snapshot, startup, dbsrc, dbdst);
|
|
p = 0;
|
|
len = sizeof(*msg) + 2*sizeof(uint32_t) + strlen(dbsrc) + 1 +
|
|
strlen(dbdst) + 1;
|
|
if ((msg = (struct clicon_msg *)chunk(len, label)) == NULL){
|
|
clicon_err(OE_PROTO, errno, "%s: chunk", __FUNCTION__);
|
|
return NULL;
|
|
}
|
|
memset(msg, 0, len);
|
|
/* hdr */
|
|
msg->op_type = htons(CLICON_MSG_COMMIT);
|
|
msg->op_len = htons(len);
|
|
/* body */
|
|
tmp = htonl(snapshot);
|
|
memcpy(msg->op_body+p, &tmp, sizeof(uint32_t));
|
|
p += sizeof(uint32_t);
|
|
tmp = htonl(startup);
|
|
memcpy(msg->op_body+p, &tmp, sizeof(uint32_t));
|
|
p += sizeof(uint32_t);
|
|
strncpy(msg->op_body+p, dbsrc, len-p-hdrlen);
|
|
p += strlen(dbsrc)+1;
|
|
strncpy(msg->op_body+p, dbdst, len-p-hdrlen);
|
|
p += strlen(dbdst)+1;
|
|
return msg;
|
|
}
|
|
|
|
int
|
|
clicon_msg_commit_decode(struct clicon_msg *msg,
|
|
char **dbsrc, char **dbdst,
|
|
uint32_t *snapshot, uint32_t *startup,
|
|
const char *label)
|
|
{
|
|
int p;
|
|
uint32_t tmp;
|
|
|
|
p = 0;
|
|
/* body */
|
|
memcpy(&tmp, msg->op_body+p, sizeof(uint32_t));
|
|
*snapshot = ntohl(tmp);
|
|
p += sizeof(uint32_t);
|
|
memcpy(&tmp, msg->op_body+p, sizeof(uint32_t));
|
|
*startup = ntohl(tmp);
|
|
p += sizeof(uint32_t);
|
|
if ((*dbsrc = chunk_sprintf(label, "%s", msg->op_body+p)) == NULL){
|
|
clicon_err(OE_PROTO, errno, "%s: chunk_sprintf",
|
|
__FUNCTION__);
|
|
return -1;
|
|
}
|
|
p += strlen(*dbsrc)+1;
|
|
if ((*dbdst = chunk_sprintf(label, "%s", msg->op_body+p)) == NULL){
|
|
clicon_err(OE_PROTO, errno, "%s: chunk_sprintf",
|
|
__FUNCTION__);
|
|
return -1;
|
|
}
|
|
p += strlen(*dbdst)+1;
|
|
clicon_debug(2, "%s: snapshot: %d startup: %d dbsrc: %s dbdst: %s",
|
|
__FUNCTION__,
|
|
*snapshot, *startup, *dbsrc, *dbdst);
|
|
return 0;
|
|
}
|
|
|
|
struct clicon_msg *
|
|
clicon_msg_validate_encode(char *db, const char *label)
|
|
{
|
|
struct clicon_msg *msg;
|
|
uint16_t len;
|
|
int hdrlen = sizeof(*msg);
|
|
|
|
clicon_debug(2, "%s: db: %s", __FUNCTION__, db);
|
|
len = sizeof(*msg) + strlen(db) + 1;
|
|
if ((msg = (struct clicon_msg *)chunk(len, label)) == NULL){
|
|
clicon_err(OE_PROTO, errno, "%s: chunk", __FUNCTION__);
|
|
return NULL;
|
|
}
|
|
memset(msg, 0, len);
|
|
/* hdr */
|
|
msg->op_type = htons(CLICON_MSG_VALIDATE);
|
|
msg->op_len = htons(len);
|
|
/* body */
|
|
strncpy(msg->op_body, db, len-hdrlen);
|
|
return msg;
|
|
}
|
|
|
|
int
|
|
clicon_msg_validate_decode(struct clicon_msg *msg, char **db, const char *label)
|
|
{
|
|
/* body */
|
|
if ((*db = chunk_sprintf(label, "%s", msg->op_body)) == NULL){
|
|
clicon_err(OE_PROTO, errno, "%s: chunk_sprintf", __FUNCTION__);
|
|
return -1;
|
|
}
|
|
clicon_debug(2, "%s: db: %s", __FUNCTION__, *db);
|
|
return 0;
|
|
}
|
|
|
|
|
|
struct clicon_msg *
|
|
clicon_msg_change_encode(char *db,
|
|
uint32_t op,
|
|
char *key,
|
|
char *str,
|
|
uint32_t str_len,
|
|
const char *label)
|
|
{
|
|
struct clicon_msg *msg;
|
|
uint16_t len;
|
|
int hdrlen = sizeof(*msg);
|
|
int p;
|
|
uint32_t tmp;
|
|
|
|
clicon_debug(2, "%s: op: %d str_len: %d db: %s key: '%s'",
|
|
__FUNCTION__,
|
|
op, str_len, db, key);
|
|
p = 0;
|
|
len = sizeof(*msg) + 2*sizeof(uint32_t) + strlen(db) + 1 +
|
|
strlen(key) + 1 + str_len;
|
|
if ((msg = (struct clicon_msg *)chunk(len, label)) == NULL){
|
|
clicon_err(OE_PROTO, errno, "%s: chunk", __FUNCTION__);
|
|
return NULL;
|
|
}
|
|
memset(msg, 0, len);
|
|
/* hdr */
|
|
msg->op_type = htons(CLICON_MSG_CHANGE);
|
|
msg->op_len = htons(len);
|
|
|
|
/* body */
|
|
tmp = htonl(op);
|
|
memcpy(msg->op_body+p, &tmp, sizeof(uint32_t));
|
|
p += sizeof(uint32_t);
|
|
|
|
tmp = htonl(str_len);
|
|
memcpy(msg->op_body+p, &tmp, sizeof(uint32_t));
|
|
p += sizeof(uint32_t);
|
|
strncpy(msg->op_body+p, db, len-p-hdrlen);
|
|
p += strlen(db)+1;
|
|
strncpy(msg->op_body+p, key, len-p-hdrlen);
|
|
p += strlen(key)+1;
|
|
memcpy(msg->op_body+p, str, str_len);
|
|
p += str_len;
|
|
return msg;
|
|
}
|
|
|
|
int
|
|
clicon_msg_change_decode(struct clicon_msg *msg,
|
|
char **db,
|
|
uint32_t *op,
|
|
char **key,
|
|
char **str,
|
|
uint32_t *str_len,
|
|
const char *label)
|
|
{
|
|
int p;
|
|
uint32_t tmp;
|
|
|
|
p = 0;
|
|
/* body */
|
|
memcpy(&tmp, msg->op_body+p, sizeof(uint32_t));
|
|
*op = ntohl(tmp);
|
|
p += sizeof(uint32_t);
|
|
|
|
memcpy(&tmp, msg->op_body+p, sizeof(uint32_t));
|
|
*str_len = ntohl(tmp);
|
|
p += sizeof(uint32_t);
|
|
|
|
if ((*db = chunk_sprintf(label, "%s", msg->op_body+p)) == NULL){
|
|
clicon_err(OE_PROTO, errno, "%s: chunk_sprintf",
|
|
__FUNCTION__);
|
|
return -1;
|
|
}
|
|
p += strlen(*db)+1;
|
|
if ((*key = chunk_sprintf(label, "%s", msg->op_body+p)) == NULL){
|
|
clicon_err(OE_PROTO, errno, "%s: chunk_sprintf",
|
|
__FUNCTION__);
|
|
return -1;
|
|
}
|
|
p += strlen(*key)+1;
|
|
|
|
if (*str_len){
|
|
if ((*str = chunk(*str_len, label)) == NULL){
|
|
clicon_err(OE_PROTO, errno, "%s: chunk",
|
|
__FUNCTION__);
|
|
return -1;
|
|
}
|
|
memcpy(*str, msg->op_body+p, *str_len);
|
|
p += *str_len;
|
|
}
|
|
else
|
|
*str = NULL;
|
|
clicon_debug(2, "%s: op: %d str_len: %d db: %s key: '%s'",
|
|
__FUNCTION__,
|
|
*op, *str_len, *db, *key);
|
|
return 0;
|
|
}
|
|
|
|
/*! Encode xmlput / edit of database content
|
|
* @param[in] db Name of database
|
|
* @param[in] op set|merge|delete. See lv_op_t
|
|
* @param[in] xml XML data string
|
|
* @param[in] label Memory chunk label
|
|
* @retval msg Encoded message
|
|
* @retval NULL Error
|
|
*/
|
|
struct clicon_msg *
|
|
clicon_msg_xmlput_encode(char *db,
|
|
uint32_t op,
|
|
char *xml,
|
|
const char *label)
|
|
{
|
|
struct clicon_msg *msg;
|
|
uint16_t len;
|
|
int hdrlen = sizeof(*msg);
|
|
int p;
|
|
uint32_t tmp;
|
|
|
|
clicon_debug(2, "%s: op: %d db: %s xml: %s",
|
|
__FUNCTION__,
|
|
op, db, xml);
|
|
p = 0;
|
|
hdrlen = sizeof(*msg);
|
|
len = sizeof(*msg) + sizeof(uint32_t) + strlen(db) + 1 + strlen(xml) + 1;
|
|
if ((msg = (struct clicon_msg *)chunk(len, label)) == NULL){
|
|
clicon_err(OE_PROTO, errno, "%s: chunk", __FUNCTION__);
|
|
return NULL;
|
|
}
|
|
memset(msg, 0, len);
|
|
/* hdr */
|
|
msg->op_type = htons(CLICON_MSG_XMLPUT);
|
|
msg->op_len = htons(len);
|
|
/* body */
|
|
tmp = htonl(op);
|
|
memcpy(msg->op_body+p, &tmp, sizeof(uint32_t));
|
|
p += sizeof(uint32_t);
|
|
|
|
strncpy(msg->op_body+p, db, len-p-hdrlen);
|
|
p += strlen(db)+1;
|
|
strncpy(msg->op_body+p, xml, len-p-hdrlen);
|
|
p += strlen(xml)+1;
|
|
return msg;
|
|
}
|
|
|
|
/*! Decode xmlput / edit of database content
|
|
* @param[in] msg Incoming message to be decoded
|
|
* @param[out] db Name of database
|
|
* @param[out] op set|merge|delete. See lv_op_t
|
|
* @param[out] xml XML data string
|
|
* @param[in] label Memory chunk label
|
|
* @retval 0 OK
|
|
* @retval -1 Error
|
|
*/
|
|
int
|
|
clicon_msg_xmlput_decode(struct clicon_msg *msg,
|
|
char **db,
|
|
uint32_t *op,
|
|
char **xml,
|
|
const char *label)
|
|
{
|
|
int p;
|
|
uint32_t tmp;
|
|
|
|
p = 0;
|
|
/* body */
|
|
memcpy(&tmp, msg->op_body+p, sizeof(uint32_t));
|
|
*op = ntohl(tmp);
|
|
p += sizeof(uint32_t);
|
|
|
|
if ((*db = chunk_sprintf(label, "%s", msg->op_body+p)) == NULL){
|
|
clicon_err(OE_PROTO, errno, "%s: chunk_sprintf",
|
|
__FUNCTION__);
|
|
return -1;
|
|
}
|
|
p += strlen(*db)+1;
|
|
if ((*xml = chunk_sprintf(label, "%s", msg->op_body+p)) == NULL){
|
|
clicon_err(OE_PROTO, errno, "%s: chunk_sprintf",
|
|
__FUNCTION__);
|
|
return -1;
|
|
}
|
|
p += strlen(*xml)+1;
|
|
clicon_debug(2, "%s: op: %d db: %s xml: %s",
|
|
__FUNCTION__,
|
|
*op, *db, *xml);
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
struct clicon_msg *
|
|
clicon_msg_save_encode(char *db, uint32_t snapshot, char *filename,
|
|
const char *label)
|
|
{
|
|
struct clicon_msg *msg;
|
|
uint16_t len;
|
|
int hdrlen = sizeof(*msg);
|
|
int p;
|
|
uint32_t tmp;
|
|
|
|
clicon_debug(2, "%s: snapshot: %d db: %s filename: %s",
|
|
__FUNCTION__,
|
|
snapshot, db, filename);
|
|
p = 0;
|
|
hdrlen = sizeof(*msg);
|
|
len = sizeof(*msg) + sizeof(uint32_t) + strlen(db) + 1;
|
|
if (!snapshot)
|
|
len += strlen(filename) + 1;
|
|
if ((msg = (struct clicon_msg *)chunk(len, label)) == NULL){
|
|
clicon_err(OE_PROTO, errno, "%s: chunk", __FUNCTION__);
|
|
return NULL;
|
|
}
|
|
memset(msg, 0, len);
|
|
/* hdr */
|
|
msg->op_type = htons(CLICON_MSG_SAVE);
|
|
msg->op_len = htons(len);
|
|
/* body */
|
|
tmp = htonl(snapshot);
|
|
memcpy(msg->op_body+p, &tmp, sizeof(uint32_t));
|
|
p += sizeof(uint32_t);
|
|
|
|
strncpy(msg->op_body+p, db, len-p-hdrlen);
|
|
p += strlen(db)+1;
|
|
if (!snapshot){
|
|
strncpy(msg->op_body+p, filename, len-p-hdrlen);
|
|
p += strlen(filename)+1;
|
|
}
|
|
return msg;
|
|
}
|
|
|
|
int
|
|
clicon_msg_save_decode(struct clicon_msg *msg,
|
|
char **db, uint32_t *snapshot, char **filename,
|
|
const char *label)
|
|
{
|
|
int p;
|
|
uint32_t tmp;
|
|
|
|
p = 0;
|
|
/* body */
|
|
memcpy(&tmp, msg->op_body+p, sizeof(uint32_t));
|
|
*snapshot = ntohl(tmp);
|
|
p += sizeof(uint32_t);
|
|
|
|
if ((*db = chunk_sprintf(label, "%s", msg->op_body+p)) == NULL){
|
|
clicon_err(OE_PROTO, errno, "%s: chunk_sprintf",
|
|
__FUNCTION__);
|
|
return -1;
|
|
}
|
|
p += strlen(*db)+1;
|
|
if (*snapshot == 0){
|
|
if ((*filename = chunk_sprintf(label, "%s", msg->op_body+p)) == NULL){
|
|
clicon_err(OE_PROTO, errno, "%s: chunk_sprintf",
|
|
__FUNCTION__);
|
|
return -1;
|
|
}
|
|
p += strlen(*filename)+1;
|
|
}
|
|
clicon_debug(2, "%s: snapshot: %d db: %s filename: %s",
|
|
__FUNCTION__,
|
|
*snapshot, *db, *filename);
|
|
return 0;
|
|
}
|
|
|
|
struct clicon_msg *
|
|
clicon_msg_load_encode(int replace, char *db, char *filename, const char *label)
|
|
{
|
|
struct clicon_msg *msg;
|
|
int hdrlen = sizeof(*msg);
|
|
uint16_t len;
|
|
uint32_t tmp;
|
|
int p;
|
|
|
|
clicon_debug(2, "%s: replace: %d db: %s filename: %s",
|
|
__FUNCTION__,
|
|
replace, db, filename);
|
|
p = 0;
|
|
len = sizeof(*msg) + sizeof(uint32_t) + strlen(db) + 1 + strlen(filename) + 1;
|
|
if ((msg = (struct clicon_msg *)chunk(len, label)) == NULL){
|
|
clicon_err(OE_PROTO, errno, "%s: chunk", __FUNCTION__);
|
|
return NULL;
|
|
}
|
|
memset(msg, 0, len);
|
|
/* hdr */
|
|
msg->op_type = htons(CLICON_MSG_LOAD);
|
|
msg->op_len = htons(len);
|
|
/* body */
|
|
tmp = htonl(replace);
|
|
memcpy(msg->op_body+p, &tmp, sizeof(uint32_t));
|
|
p += sizeof(uint32_t);
|
|
|
|
strncpy(msg->op_body+p, db, len-p-hdrlen);
|
|
p += strlen(db)+1;
|
|
strncpy(msg->op_body+p, filename, len-p-hdrlen);
|
|
p += strlen(filename)+1;
|
|
return msg;
|
|
}
|
|
|
|
int
|
|
clicon_msg_load_decode(struct clicon_msg *msg,
|
|
int *replace,
|
|
char **db,
|
|
char **filename,
|
|
const char *label)
|
|
{
|
|
int p;
|
|
uint32_t tmp;
|
|
|
|
p = 0;
|
|
/* body */
|
|
memcpy(&tmp, msg->op_body+p, sizeof(uint32_t));
|
|
*replace = ntohl(tmp);
|
|
p += sizeof(uint32_t);
|
|
if ((*db = chunk_sprintf(label, "%s", msg->op_body+p)) == NULL){
|
|
clicon_err(OE_PROTO, errno, "%s: chunk_sprintf",
|
|
__FUNCTION__);
|
|
return -1;
|
|
}
|
|
p += strlen(*db)+1;
|
|
if ((*filename = chunk_sprintf(label, "%s", msg->op_body+p)) == NULL){
|
|
clicon_err(OE_PROTO, errno, "%s: chunk_sprintf",
|
|
__FUNCTION__);
|
|
return -1;
|
|
}
|
|
p += strlen(*filename)+1;
|
|
clicon_debug(2, "%s: %d db: %s filename: %s",
|
|
__FUNCTION__,
|
|
ntohs(msg->op_type),
|
|
*db, *filename);
|
|
return 0;
|
|
}
|
|
|
|
struct clicon_msg *
|
|
clicon_msg_copy_encode(char *db_src, char *db_dst,
|
|
const char *label)
|
|
{
|
|
struct clicon_msg *msg;
|
|
int hdrlen = sizeof(*msg);
|
|
uint16_t len;
|
|
int p;
|
|
|
|
clicon_debug(2, "%s: db_src: %s db_dst: %s",
|
|
__FUNCTION__,
|
|
db_src, db_dst);
|
|
p = 0;
|
|
len = hdrlen + strlen(db_src) + 1 + strlen(db_dst) + 1;
|
|
if ((msg = (struct clicon_msg *)chunk(len, label)) == NULL){
|
|
clicon_err(OE_PROTO, errno, "%s: chunk", __FUNCTION__);
|
|
return NULL;
|
|
}
|
|
memset(msg, 0, len);
|
|
/* hdr */
|
|
msg->op_type = htons(CLICON_MSG_COPY);
|
|
msg->op_len = htons(len);
|
|
/* body */
|
|
strncpy(msg->op_body+p, db_src, len-p-hdrlen);
|
|
p += strlen(db_src)+1;
|
|
strncpy(msg->op_body+p, db_dst, len-p-hdrlen);
|
|
p += strlen(db_dst)+1;
|
|
return msg;
|
|
}
|
|
|
|
int
|
|
clicon_msg_copy_decode(struct clicon_msg *msg,
|
|
char **db_src, char **db_dst,
|
|
const char *label)
|
|
{
|
|
int p;
|
|
|
|
p = 0;
|
|
/* body */
|
|
if ((*db_src = chunk_sprintf(label, "%s", msg->op_body+p)) == NULL){
|
|
clicon_err(OE_PROTO, errno, "%s: chunk_sprintf",
|
|
__FUNCTION__);
|
|
return -1;
|
|
}
|
|
p += strlen(*db_src)+1;
|
|
|
|
if ((*db_dst = chunk_sprintf(label, "%s", msg->op_body+p)) == NULL){
|
|
clicon_err(OE_PROTO, errno, "%s: chunk_sprintf",
|
|
__FUNCTION__);
|
|
return -1;
|
|
}
|
|
p += strlen(*db_dst)+1;
|
|
clicon_debug(2, "%s: db_src: %s db_dst: %s",
|
|
__FUNCTION__,
|
|
*db_src, *db_dst);
|
|
return 0;
|
|
}
|
|
|
|
struct clicon_msg *
|
|
clicon_msg_kill_encode(uint32_t session_id, const char *label)
|
|
{
|
|
struct clicon_msg *msg;
|
|
uint16_t len;
|
|
int p;
|
|
uint32_t tmp;
|
|
|
|
clicon_debug(2, "%s: %d", __FUNCTION__, session_id);
|
|
p = 0;
|
|
len = sizeof(*msg) + sizeof(uint32_t);
|
|
if ((msg = (struct clicon_msg *)chunk(len, label)) == NULL){
|
|
clicon_err(OE_PROTO, errno, "%s: chunk", __FUNCTION__);
|
|
return NULL;
|
|
}
|
|
memset(msg, 0, len);
|
|
/* hdr */
|
|
msg->op_type = htons(CLICON_MSG_KILL);
|
|
msg->op_len = htons(len);
|
|
/* body */
|
|
tmp = htonl(session_id);
|
|
memcpy(msg->op_body+p, &tmp, sizeof(uint32_t));
|
|
p += sizeof(uint32_t);
|
|
return msg;
|
|
|
|
}
|
|
|
|
int
|
|
clicon_msg_kill_decode(struct clicon_msg *msg,
|
|
uint32_t *session_id,
|
|
const char *label)
|
|
{
|
|
int p;
|
|
uint32_t tmp;
|
|
|
|
p = 0;
|
|
/* body */
|
|
memcpy(&tmp, msg->op_body+p, sizeof(uint32_t));
|
|
*session_id = ntohl(tmp);
|
|
p += sizeof(uint32_t);
|
|
clicon_debug(2, "%s: session-id: %u", __FUNCTION__, *session_id);
|
|
return 0;
|
|
}
|
|
|
|
struct clicon_msg *
|
|
clicon_msg_debug_encode(uint32_t level, const char *label)
|
|
{
|
|
struct clicon_msg *msg;
|
|
uint16_t len;
|
|
int p;
|
|
uint32_t tmp;
|
|
|
|
clicon_debug(2, "%s: %d", __FUNCTION__, label);
|
|
p = 0;
|
|
len = sizeof(*msg) + sizeof(uint32_t);
|
|
if ((msg = (struct clicon_msg *)chunk(len, label)) == NULL){
|
|
clicon_err(OE_PROTO, errno, "%s: chunk", __FUNCTION__);
|
|
return NULL;
|
|
}
|
|
memset(msg, 0, len);
|
|
/* hdr */
|
|
msg->op_type = htons(CLICON_MSG_DEBUG);
|
|
msg->op_len = htons(len);
|
|
/* body */
|
|
tmp = htonl(level);
|
|
memcpy(msg->op_body+p, &tmp, sizeof(uint32_t));
|
|
p += sizeof(uint32_t);
|
|
return msg;
|
|
|
|
}
|
|
|
|
int
|
|
clicon_msg_debug_decode(struct clicon_msg *msg,
|
|
uint32_t *level,
|
|
const char *label)
|
|
{
|
|
int p;
|
|
uint32_t tmp;
|
|
|
|
p = 0;
|
|
/* body */
|
|
memcpy(&tmp, msg->op_body+p, sizeof(uint32_t));
|
|
*level = ntohl(tmp);
|
|
p += sizeof(uint32_t);
|
|
clicon_debug(2, "%s: session-id: %u", __FUNCTION__, *level);
|
|
return 0;
|
|
}
|
|
|
|
|
|
struct clicon_msg *
|
|
clicon_msg_call_encode(uint16_t op,
|
|
char *plugin,
|
|
char *func,
|
|
uint16_t arglen,
|
|
void *arg,
|
|
const char *label)
|
|
{
|
|
struct clicon_msg *msg;
|
|
struct clicon_msg_call_req *req;
|
|
int hdrlen = sizeof(*msg);
|
|
int len;
|
|
|
|
clicon_debug(2, "%s: %d plugin: %s func: %s arglen: %d",
|
|
__FUNCTION__, op, plugin, func, arglen);
|
|
len =
|
|
hdrlen +
|
|
sizeof(struct clicon_msg_call_req) +
|
|
strlen(plugin) + 1 +
|
|
strlen(func) + 1 +
|
|
arglen;
|
|
if ((msg = (struct clicon_msg *)chunk(len, label)) == NULL){
|
|
clicon_err(OE_PROTO, errno, "%s: chunk", __FUNCTION__);
|
|
return NULL;
|
|
}
|
|
memset(msg, 0, len);
|
|
/* hdr */
|
|
msg->op_type = htons(CLICON_MSG_CALL);
|
|
msg->op_len = htons(len);
|
|
/* req */
|
|
req = (struct clicon_msg_call_req *)msg->op_body;
|
|
req->cr_len = htons(len - hdrlen);
|
|
req->cr_op = htons(op);
|
|
req->cr_plugin = req->cr_data;
|
|
strncpy(req->cr_plugin, plugin, strlen(plugin));
|
|
req->cr_func = req->cr_plugin + strlen(req->cr_plugin) + 1;
|
|
strncpy(req->cr_func, func, strlen(func));
|
|
req->cr_arglen = htons(arglen);
|
|
req->cr_arg = req->cr_func + strlen(req->cr_func) + 1;
|
|
memcpy(req->cr_arg, arg, arglen);
|
|
|
|
return msg;
|
|
|
|
}
|
|
|
|
int
|
|
clicon_msg_call_decode(struct clicon_msg *msg,
|
|
struct clicon_msg_call_req **req,
|
|
const char *label)
|
|
{
|
|
uint16_t len;
|
|
struct clicon_msg_call_req *r;
|
|
|
|
r = (struct clicon_msg_call_req *)msg->op_body;
|
|
len = ntohs(r->cr_len);
|
|
if ((*req = chunk(len, label)) == NULL) {
|
|
clicon_err(OE_PROTO, errno, "%s: chunk", __FUNCTION__);
|
|
return -1;
|
|
}
|
|
memcpy(*req, r, len);
|
|
(*req)->cr_len = ntohs(r->cr_len);
|
|
(*req)->cr_op = ntohs(r->cr_op);
|
|
(*req)->cr_arglen = ntohs(r->cr_arglen);
|
|
(*req)->cr_plugin = (*req)->cr_data;
|
|
(*req)->cr_func = (*req)->cr_plugin + strlen((*req)->cr_plugin) +1;
|
|
(*req)->cr_arg = (*req)->cr_func + strlen((*req)->cr_func) +1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
struct clicon_msg *
|
|
clicon_msg_subscription_encode(int status,
|
|
char *stream,
|
|
enum format_enum format,
|
|
char *filter,
|
|
const char *label)
|
|
{
|
|
struct clicon_msg *msg;
|
|
uint16_t len;
|
|
int hdrlen = sizeof(*msg);
|
|
int p;
|
|
int tmp;
|
|
|
|
clicon_debug(2, "%s: %d %d %s %s", __FUNCTION__, status, format, stream, filter);
|
|
p = 0;
|
|
assert(filter);
|
|
len = hdrlen + sizeof(uint32_t) + sizeof(uint32_t) + strlen(stream) + 1 + strlen(filter) + 1;
|
|
if ((msg = (struct clicon_msg *)chunk(len, label)) == NULL){
|
|
clicon_err(OE_PROTO, errno, "%s: chunk", __FUNCTION__);
|
|
return NULL;
|
|
}
|
|
memset(msg, 0, len);
|
|
/* hdr */
|
|
msg->op_type = htons(CLICON_MSG_SUBSCRIPTION);
|
|
msg->op_len = htons(len);
|
|
/* body */
|
|
tmp = htonl(status);
|
|
memcpy(msg->op_body+p, &tmp, sizeof(int));
|
|
p += sizeof(int);
|
|
|
|
tmp = htonl(format);
|
|
memcpy(msg->op_body+p, &tmp, sizeof(int));
|
|
p += sizeof(int);
|
|
|
|
strncpy(msg->op_body+p, stream, len-p-hdrlen);
|
|
p += strlen(stream)+1;
|
|
|
|
strncpy(msg->op_body+p, filter, len-p-hdrlen);
|
|
p += strlen(filter)+1;
|
|
|
|
return msg;
|
|
}
|
|
|
|
int
|
|
clicon_msg_subscription_decode(struct clicon_msg *msg,
|
|
int *status,
|
|
char **stream,
|
|
enum format_enum *format,
|
|
char **filter,
|
|
const char *label)
|
|
{
|
|
int p;
|
|
int tmp;
|
|
|
|
p = 0;
|
|
/* body */
|
|
memcpy(&tmp, msg->op_body+p, sizeof(int));
|
|
*status = ntohl(tmp);
|
|
p += sizeof(int);
|
|
|
|
memcpy(&tmp, msg->op_body+p, sizeof(int));
|
|
*format = ntohl(tmp);
|
|
p += sizeof(int);
|
|
|
|
if ((*stream = chunk_sprintf(label, "%s", msg->op_body+p)) == NULL){
|
|
clicon_err(OE_PROTO, errno, "%s: chunk_sprintf",
|
|
__FUNCTION__);
|
|
return -1;
|
|
}
|
|
p += strlen(*stream)+1;
|
|
|
|
if ((*filter = chunk_sprintf(label, "%s", msg->op_body+p)) == NULL){
|
|
clicon_err(OE_PROTO, errno, "%s: chunk_sprintf",
|
|
__FUNCTION__);
|
|
return -1;
|
|
}
|
|
p += strlen(*filter)+1;
|
|
clicon_debug(2, "%s: %d %s %d %s", __FUNCTION__, *status, *filter, *stream, *filter);
|
|
return 0;
|
|
}
|
|
|
|
struct clicon_msg *
|
|
clicon_msg_notify_encode(int level, char *event, const char *label)
|
|
{
|
|
struct clicon_msg *msg;
|
|
uint16_t len;
|
|
int hdrlen = sizeof(*msg);
|
|
int p;
|
|
int tmp;
|
|
|
|
clicon_debug(2, "%s: %d %s", __FUNCTION__, level, event);
|
|
p = 0;
|
|
hdrlen = sizeof(*msg);
|
|
len = sizeof(*msg) + sizeof(uint32_t) + strlen(event) + 1;
|
|
if ((msg = (struct clicon_msg *)chunk(len, label)) == NULL){
|
|
clicon_err(OE_PROTO, errno, "%s: chunk", __FUNCTION__);
|
|
return NULL;
|
|
}
|
|
memset(msg, 0, len);
|
|
/* hdr */
|
|
msg->op_type = htons(CLICON_MSG_NOTIFY);
|
|
msg->op_len = htons(len);
|
|
/* body */
|
|
tmp = htonl(level);
|
|
memcpy(msg->op_body+p, &tmp, sizeof(int));
|
|
p += sizeof(int);
|
|
strncpy(msg->op_body+p, event, len-p-hdrlen);
|
|
p += strlen(event)+1;
|
|
|
|
return msg;
|
|
}
|
|
|
|
int
|
|
clicon_msg_notify_decode(struct clicon_msg *msg,
|
|
int *level, char **event,
|
|
const char *label)
|
|
{
|
|
int p;
|
|
int tmp;
|
|
|
|
p = 0;
|
|
/* body */
|
|
memcpy(&tmp, msg->op_body+p, sizeof(int));
|
|
*level = ntohl(tmp);
|
|
p += sizeof(int);
|
|
if ((*event = chunk_sprintf(label, "%s", msg->op_body+p)) == NULL){
|
|
clicon_err(OE_PROTO, errno, "%s: chunk_sprintf",
|
|
__FUNCTION__);
|
|
return -1;
|
|
}
|
|
p += strlen(*event)+1;
|
|
clicon_debug(2, "%s: %d %s", __FUNCTION__, *level, *event);
|
|
return 0;
|
|
}
|
|
|
|
struct clicon_msg *
|
|
clicon_msg_err_encode(uint32_t err, uint32_t suberr, char *reason, const char *label)
|
|
{
|
|
struct clicon_msg *msg;
|
|
uint16_t len;
|
|
int hdrlen = sizeof(*msg);
|
|
int p;
|
|
uint32_t tmp;
|
|
|
|
clicon_debug(2, "%s: %d %d %s", __FUNCTION__, err, suberr, reason);
|
|
p = 0;
|
|
hdrlen = sizeof(*msg);
|
|
len = sizeof(*msg) + 2*sizeof(uint32_t) + strlen(reason) + 1;
|
|
if ((msg = (struct clicon_msg *)chunk(len, label)) == NULL){
|
|
clicon_err(OE_PROTO, errno, "%s: chunk", __FUNCTION__);
|
|
return NULL;
|
|
}
|
|
memset(msg, 0, len);
|
|
/* hdr */
|
|
msg->op_type = htons(CLICON_MSG_ERR);
|
|
msg->op_len = htons(len);
|
|
/* body */
|
|
tmp = htonl(err);
|
|
memcpy(msg->op_body+p, &tmp, sizeof(uint32_t));
|
|
p += sizeof(uint32_t);
|
|
tmp = htonl(suberr);
|
|
memcpy(msg->op_body+p, &tmp, sizeof(uint32_t));
|
|
p += sizeof(uint32_t);
|
|
strncpy(msg->op_body+p, reason, len-p-hdrlen);
|
|
p += strlen(reason)+1;
|
|
|
|
return msg;
|
|
|
|
}
|
|
|
|
int
|
|
clicon_msg_err_decode(struct clicon_msg *msg,
|
|
uint32_t *err, uint32_t *suberr, char **reason,
|
|
const char *label)
|
|
{
|
|
int p;
|
|
uint32_t tmp;
|
|
|
|
p = 0;
|
|
/* body */
|
|
memcpy(&tmp, msg->op_body+p, sizeof(uint32_t));
|
|
*err = ntohl(tmp);
|
|
p += sizeof(uint32_t);
|
|
memcpy(&tmp, msg->op_body+p, sizeof(uint32_t));
|
|
*suberr = ntohl(tmp);
|
|
p += sizeof(uint32_t);
|
|
if ((*reason = chunk_sprintf(label, "%s", msg->op_body+p)) == NULL){
|
|
clicon_err(OE_PROTO, errno, "%s: chunk_sprintf",
|
|
__FUNCTION__);
|
|
return -1;
|
|
}
|
|
p += strlen(*reason)+1;
|
|
clicon_debug(2, "%s: %d %d %s",
|
|
__FUNCTION__,
|
|
*err, *suberr, *reason);
|
|
return 0;
|
|
}
|
|
|