Merging upstream version 3.5.5 (Closes: #1098233).
Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
parent
c86ae7dcba
commit
6af28b7e8e
144 changed files with 43534 additions and 11497 deletions
266
examples/client.c
Normal file
266
examples/client.c
Normal file
|
@ -0,0 +1,266 @@
|
|||
/**
|
||||
* @file client.c
|
||||
* @author Roman Janota <xjanot04@fit.vutbr.cz>
|
||||
* @brief libnetconf2 client example
|
||||
*
|
||||
* @copyright
|
||||
* Copyright (c) 2022 CESNET, z.s.p.o.
|
||||
*
|
||||
* This source code is licensed under BSD 3-Clause License (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://opensource.org/licenses/BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include "example.h"
|
||||
|
||||
#include <getopt.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <libyang/libyang.h>
|
||||
|
||||
#include "log.h"
|
||||
#include "messages_client.h"
|
||||
#include "netconf.h"
|
||||
#include "session_client.h"
|
||||
#include "session_client_ch.h"
|
||||
|
||||
static void
|
||||
help_print()
|
||||
{
|
||||
printf("Example usage:\n"
|
||||
" client get\n"
|
||||
"\n"
|
||||
" Available options:\n"
|
||||
" -h, --help\t \tPrint usage help.\n"
|
||||
" -p, --port\t\t<port>\tSpecify the port to connect to.\n"
|
||||
" -u, --unix-path\t<path>\tConnect to a UNIX socket located at <path>.\n"
|
||||
" -P, --ssh-pubkey\t<path>\tSet the path to an SSH Public key.\n"
|
||||
" -i, --ssh-privkey\t<path>\tSet the path to an SSH Private key.\n\n"
|
||||
" Available RPCs:\n"
|
||||
" get [xpath-filter]\t\t\t\t\t send a <get> RPC with optional XPath filter\n"
|
||||
" get-config [datastore] [xpath-filter]\t\t send a <get-config> RPC with optional XPath filter and datastore, the default datastore is \"running\" \n\n");
|
||||
}
|
||||
|
||||
static enum NC_DATASTORE_TYPE
|
||||
string2datastore(const char *str)
|
||||
{
|
||||
if (!str) {
|
||||
return NC_DATASTORE_RUNNING;
|
||||
}
|
||||
|
||||
if (!strcmp(str, "candidate")) {
|
||||
return NC_DATASTORE_CANDIDATE;
|
||||
} else if (!strcmp(str, "running")) {
|
||||
return NC_DATASTORE_RUNNING;
|
||||
} else if (!strcmp(str, "startup")) {
|
||||
return NC_DATASTORE_STARTUP;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
send_rpc(struct nc_session *session, NC_RPC_TYPE rpc_type, const char *param1, const char *param2)
|
||||
{
|
||||
enum NC_DATASTORE_TYPE datastore;
|
||||
int r = 0, rc = 0;
|
||||
uint64_t msg_id = 0;
|
||||
struct lyd_node *envp = NULL, *op = NULL;
|
||||
struct nc_rpc *rpc = NULL;
|
||||
|
||||
/* decide which type of RPC to send */
|
||||
switch (rpc_type) {
|
||||
case NC_RPC_GET:
|
||||
/* create get RPC with an optional filter */
|
||||
rpc = nc_rpc_get(param1, NC_WD_UNKNOWN, NC_PARAMTYPE_CONST);
|
||||
break;
|
||||
|
||||
case NC_RPC_GETCONFIG:
|
||||
/* create get-config RPC with a source datastore and an optional filter */
|
||||
datastore = string2datastore(param1);
|
||||
if (!datastore) {
|
||||
ERR_MSG_CLEANUP("Invalid name of a datastore. Use candidate, running, startup or neither.\n");
|
||||
}
|
||||
rpc = nc_rpc_getconfig(datastore, param2, NC_WD_UNKNOWN, NC_PARAMTYPE_CONST);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (!rpc) {
|
||||
ERR_MSG_CLEANUP("Error while creating a RPC\n");
|
||||
}
|
||||
|
||||
/* send the RPC on the session and remember NETCONF message ID */
|
||||
r = nc_send_rpc(session, rpc, 100, &msg_id);
|
||||
if (r != NC_MSG_RPC) {
|
||||
ERR_MSG_CLEANUP("Couldn't send a RPC\n");
|
||||
}
|
||||
|
||||
/* receive the server's reply with the expected message ID
|
||||
* as separate rpc-reply NETCONF envelopes and the parsed YANG output itself, if any */
|
||||
r = nc_recv_reply(session, rpc, msg_id, 100, &envp, &op);
|
||||
if (r != NC_MSG_REPLY) {
|
||||
ERR_MSG_CLEANUP("Couldn't receive a reply from the server\n");
|
||||
}
|
||||
|
||||
/* print the whole reply */
|
||||
if (!op) {
|
||||
r = lyd_print_file(stdout, envp, LYD_XML, 0);
|
||||
} else {
|
||||
r = lyd_print_file(stdout, op, LYD_XML, 0);
|
||||
if (r) {
|
||||
ERR_MSG_CLEANUP("Couldn't print the RPC to stdout\n");
|
||||
}
|
||||
r = lyd_print_file(stdout, envp, LYD_XML, 0);
|
||||
}
|
||||
if (r) {
|
||||
ERR_MSG_CLEANUP("Couldn't print the RPC to stdout\n");
|
||||
}
|
||||
|
||||
cleanup:
|
||||
lyd_free_all(envp);
|
||||
lyd_free_all(op);
|
||||
nc_rpc_free(rpc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
int rc = 0, opt, port = 0;
|
||||
struct nc_session *session = NULL;
|
||||
const char *unix_socket_path = NULL, *rpc_parameter_1 = NULL, *rpc_parameter_2 = NULL;
|
||||
const char *ssh_pubkey_path = NULL, *ssh_privkey_path = NULL;
|
||||
|
||||
struct option options[] = {
|
||||
{"help", no_argument, NULL, 'h'},
|
||||
{"port", required_argument, NULL, 'p'},
|
||||
{"unix-path", required_argument, NULL, 'u'},
|
||||
{"ssh-pubkey", required_argument, NULL, 'P'},
|
||||
{"ssh-privkey", required_argument, NULL, 'i'},
|
||||
{"debug", no_argument, NULL, 'd'},
|
||||
{NULL, 0, NULL, 0}
|
||||
};
|
||||
|
||||
if (argc == 1) {
|
||||
help_print();
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* set the path to search for schemas */
|
||||
nc_client_set_schema_searchpath(MODULES_DIR);
|
||||
|
||||
opterr = 0;
|
||||
|
||||
while ((opt = getopt_long(argc, argv, "hp:u:P:i:d", options, NULL)) != -1) {
|
||||
switch (opt) {
|
||||
case 'h':
|
||||
help_print();
|
||||
goto cleanup;
|
||||
|
||||
case 'p':
|
||||
port = strtoul(optarg, NULL, 10);
|
||||
break;
|
||||
|
||||
case 'u':
|
||||
unix_socket_path = optarg;
|
||||
break;
|
||||
|
||||
case 'P':
|
||||
ssh_pubkey_path = optarg;
|
||||
break;
|
||||
|
||||
case 'i':
|
||||
ssh_privkey_path = optarg;
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
nc_verbosity(NC_VERB_DEBUG);
|
||||
nc_libssh_thread_verbosity(2);
|
||||
break;
|
||||
|
||||
default:
|
||||
ERR_MSG_CLEANUP("Invalid option or missing argument\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (optind == argc) {
|
||||
ERR_MSG_CLEANUP("Expected the name of RPC after options\n");
|
||||
}
|
||||
|
||||
/* check invalid args combinations */
|
||||
if (unix_socket_path && port) {
|
||||
ERR_MSG_CLEANUP("Both UNIX socket path and port specified. Please choose either SSH or UNIX.\n");
|
||||
} else if (unix_socket_path && (ssh_pubkey_path || ssh_privkey_path)) {
|
||||
ERR_MSG_CLEANUP("Both UNIX socket path and a path to key(s) specified. Please choose either SSH or UNIX.\n");
|
||||
} else if ((port == 10001) && (!ssh_pubkey_path || !ssh_privkey_path)) {
|
||||
ERR_MSG_CLEANUP("You need to specify both paths to private and public keys, if you want to connect to a publickey endpoint.\n");
|
||||
} else if ((port == 10000) && (ssh_pubkey_path || ssh_privkey_path)) {
|
||||
ERR_MSG_CLEANUP("Public or private key specified, when connecting to the password endpoint.\n");
|
||||
} else if (!unix_socket_path && !port) {
|
||||
ERR_MSG_CLEANUP("Neither UNIX socket or SSH specified.\n");
|
||||
}
|
||||
|
||||
/* connect to the server using the specified transport protocol */
|
||||
if (unix_socket_path) {
|
||||
/* it's UNIX socket */
|
||||
session = nc_connect_unix(unix_socket_path, NULL);
|
||||
} else {
|
||||
/* it must be SSH, so set the client SSH username to always be used when connecting to the server */
|
||||
if (nc_client_ssh_set_username(SSH_USERNAME)) {
|
||||
ERR_MSG_CLEANUP("Couldn't set the SSH username\n");
|
||||
}
|
||||
|
||||
if (ssh_pubkey_path && ssh_privkey_path) {
|
||||
/* set the client's SSH keypair to be used for authentication if necessary */
|
||||
if (nc_client_ssh_add_keypair(ssh_pubkey_path, ssh_privkey_path)) {
|
||||
ERR_MSG_CLEANUP("Couldn't set client's SSH keypair.\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* try to connect via SSH */
|
||||
session = nc_connect_ssh(SSH_ADDRESS, port, NULL);
|
||||
}
|
||||
if (!session) {
|
||||
ERR_MSG_CLEANUP("Couldn't connect to the server\n");
|
||||
}
|
||||
|
||||
/* sending a get RPC */
|
||||
if (!strcmp(argv[optind], "get")) {
|
||||
if (optind + 1 < argc) {
|
||||
/* use the specified XPath filter */
|
||||
rpc_parameter_1 = argv[optind + 1];
|
||||
}
|
||||
if (send_rpc(session, NC_RPC_GET, rpc_parameter_1, rpc_parameter_2)) {
|
||||
rc = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
/* sending a get-config RPC */
|
||||
} else if (!strcmp(argv[optind], "get-config")) {
|
||||
/* use the specified datastore and optional XPath filter */
|
||||
if (optind + 2 < argc) {
|
||||
rpc_parameter_1 = argv[optind + 1];
|
||||
rpc_parameter_2 = argv[optind + 2];
|
||||
} else if (optind + 1 < argc) {
|
||||
rpc_parameter_1 = argv[optind + 1];
|
||||
}
|
||||
if (send_rpc(session, NC_RPC_GETCONFIG, rpc_parameter_1, rpc_parameter_2)) {
|
||||
rc = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
} else {
|
||||
ERR_MSG_CLEANUP("Invalid name of a RPC\n");
|
||||
}
|
||||
|
||||
cleanup:
|
||||
nc_session_free(session, NULL);
|
||||
nc_client_destroy();
|
||||
return rc;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue