f3cb997dd6440b5542265554a85702ce2f9c40d5
[sim/o1-interface.git] / ntsimulator / ntsim-ng / utils / nc_client.c
1 /*************************************************************************
2 *
3 * Copyright 2020 highstreet technologies GmbH and others
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 ***************************************************************************/
17
18 #define _GNU_SOURCE
19
20 #include "nc_client.h"
21 #include "utils/log_utils.h"
22 #include "utils/sys_utils.h"
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <assert.h>
26
27 #include "core/session.h"
28
29 #include <libnetconf2/session.h>
30 #include <libnetconf2/session_client.h>
31 #include <libnetconf2/messages_client.h>
32
33 static char *nc_client_pass_cb(const char *username, const char *hostname, void *priv) {
34     nc_client_t *client = (nc_client_t *)priv;
35     return strdup(client->password);
36 }
37
38 static int nc_client_auth_hostkey_check(const char *hostname, ssh_session session, void *priv) {
39     return 0;   //auto-authorize
40 }
41
42 nc_client_t *nc_client_ssh_connect(const char *host, uint16_t port, const char *username, const char *password) {
43     assert(host);
44     assert(port > 20);
45     assert(username);
46     assert(password);
47
48     nc_client_t *client = (nc_client_t *)malloc(sizeof(nc_client_t));
49     if(client == 0) {
50         return 0;
51     }
52
53     client->edit_batch_root = 0;
54
55     nc_client_init();
56
57     nc_client_ssh_set_auth_pref(NC_SSH_AUTH_PASSWORD, 3);
58     nc_client_ssh_set_auth_pref(NC_SSH_AUTH_PUBLICKEY, -1);
59     nc_client_ssh_set_auth_pref(NC_SSH_AUTH_INTERACTIVE, -1);
60
61     nc_client_ssh_set_username(username);
62     client->password = strdup(password);
63     if(client->password == 0) {
64         free(client);
65     }
66
67     nc_client_ssh_set_auth_password_clb(nc_client_pass_cb, client);
68     nc_client_ssh_set_auth_hostkey_check_clb(nc_client_auth_hostkey_check, 0);
69
70     client->session = nc_connect_ssh(host, port, 0);
71     if(client->session == 0) {
72         log_error("nc_connect_ssh failed");
73         free(client->password);
74         free(client);
75         return 0;
76     }
77
78     return client;
79 }
80
81 int nc_client_disconnect(nc_client_t *client) {
82     assert(client);
83     
84     nc_session_free(client->session, 0);
85     free(client->password);
86     free(client);
87
88     return NTS_ERR_OK;
89 }
90
91 struct lyd_node *nc_client_send_rpc(nc_client_t *client, struct lyd_node *data, int timeout) {
92     assert(client);
93     assert(data);
94
95     struct nc_rpc *rpc;
96     struct nc_reply *reply;
97     NC_MSG_TYPE send_ret;
98     NC_MSG_TYPE reply_ret;
99     uint64_t msg_id;
100
101     char *xmldata = 0;
102     if(lyd_print_mem(&xmldata, data, LYD_XML, 0) != 0) {
103         log_error("lyd_print_mem failed");
104         return 0;
105     }
106
107     rpc = nc_rpc_act_generic_xml(xmldata, NC_PARAMTYPE_CONST);
108     if(rpc == 0) {
109         log_error("could not create rpc");
110         free(xmldata);
111         return 0;
112     }
113
114     msg_id = 0;
115     send_ret = nc_send_rpc(client->session, rpc, timeout, &msg_id);
116     if(send_ret != NC_MSG_RPC) {
117         log_error("could not send rpc");
118         free(xmldata);
119         nc_rpc_free(rpc);
120         return 0;
121     }
122
123     repeat_nc_recv_reply:
124     reply_ret = nc_recv_reply(client->session, rpc, msg_id, timeout, LYD_OPT_DESTRUCT | LYD_OPT_NOSIBLINGS, &reply);
125     if(reply_ret != NC_MSG_REPLY) {
126         if(reply_ret == NC_MSG_NOTIF) {
127             goto repeat_nc_recv_reply;
128         }
129
130         log_error("could not get rpc reply");
131         free(xmldata);
132         nc_rpc_free(rpc);
133         return 0;
134     }
135
136     if(reply->type != NC_RPL_DATA) {
137         log_error("reply has no data");
138         free(xmldata);
139         nc_rpc_free(rpc);
140         nc_reply_free(reply);
141         return 0;
142     }
143
144     char *ret_data_xml = strdup("");    //libyang does not support having the parent RPC in XML
145     struct lyd_node *chd = 0;
146     LY_TREE_FOR(((struct nc_reply_data *)reply)->data->child, chd) {
147         char *temp_xml = 0;
148         if(lyd_print_mem(&temp_xml, chd, LYD_XML, 0) != 0) {
149             log_error("lyd_print_mem failed");
150             free(ret_data_xml);
151             free(xmldata);
152             nc_rpc_free(rpc);
153             nc_reply_free(reply);
154             return 0;
155         }
156
157         ret_data_xml = (char *)realloc(ret_data_xml, sizeof(char) * (strlen(ret_data_xml) + strlen(temp_xml) + 1));
158         strcat(ret_data_xml, temp_xml);
159         free(temp_xml);
160     }
161     
162     free(xmldata);
163     nc_reply_free(reply);
164     nc_rpc_free(rpc);
165
166     struct lyd_node *ret_data = lyd_parse_mem(session_context, ret_data_xml, LYD_XML, LYD_OPT_RPCREPLY | LYD_OPT_NOEXTDEPS, data, 0);
167     free(ret_data_xml);
168     return ret_data;
169 }
170
171 struct lyd_node *nc_client_get_batch(nc_client_t *client, const char *xpath, int timeout) {
172     assert(client);
173     assert(xpath);
174
175     struct nc_rpc *rpc;
176     struct nc_reply *reply;
177     NC_MSG_TYPE send_ret;
178     NC_MSG_TYPE reply_ret;
179     uint64_t msg_id;
180
181     rpc = nc_rpc_get(xpath, NC_WD_UNKNOWN, NC_PARAMTYPE_CONST);
182     if(rpc == 0) {
183         log_error("could not create rpc");
184         return 0;
185     }
186
187     msg_id = 0;
188     send_ret = nc_send_rpc(client->session, rpc, timeout, &msg_id);
189     if(send_ret != NC_MSG_RPC) {
190         log_error("could not send rpc");
191         nc_rpc_free(rpc);
192         return 0;
193     }
194
195     repeat_nc_recv_reply:
196     reply_ret = 0;
197     reply_ret = nc_recv_reply(client->session, rpc, msg_id, timeout, LYD_OPT_DESTRUCT | LYD_OPT_NOSIBLINGS, &reply);
198     if(reply_ret != NC_MSG_REPLY) {
199         if(reply_ret == NC_MSG_NOTIF) {
200             goto repeat_nc_recv_reply;
201         }
202
203         log_error("could not get rpc reply");
204         nc_rpc_free(rpc);
205         return 0;
206     }
207
208     if(reply->type != NC_RPL_DATA) {
209         log_error("reply has no data");
210         nc_rpc_free(rpc);
211         nc_reply_free(reply);
212         return 0;
213     }
214
215     char *ret_data_xml = 0;
216     if(lyd_print_mem(&ret_data_xml, ((struct nc_reply_data *)reply)->data, LYD_XML, 0) != 0) {
217         log_error("lyd_print_mem failed");
218         nc_reply_free(reply);
219         nc_rpc_free(rpc);
220         return 0;
221     }
222     
223     nc_reply_free(reply);
224     nc_rpc_free(rpc);
225
226     struct lyd_node *ret_data = lyd_parse_mem(session_context, ret_data_xml, LYD_XML, LYD_OPT_DATA | LYD_OPT_NOSIBLINGS);
227     free(ret_data_xml);
228     return ret_data;
229 }
230
231 int nc_client_edit_batch(nc_client_t *client, struct lyd_node *data, int timeout) {
232     assert(client);
233     assert(data);
234
235     struct nc_rpc *rpc;
236     struct nc_reply *reply;
237     NC_MSG_TYPE send_ret;
238     NC_MSG_TYPE reply_ret;
239     uint64_t msg_id;
240
241     char *content = 0;
242     int rc = lyd_print_mem(&content, data, LYD_XML, 0);
243     if(rc != 0) {
244         log_error("lyd_print_mem failed");
245         return NTS_ERR_FAILED;
246     }
247
248     rpc = nc_rpc_edit(NC_DATASTORE_RUNNING, NC_RPC_EDIT_DFLTOP_MERGE, NC_RPC_EDIT_TESTOPT_SET, NC_RPC_EDIT_ERROPT_STOP, content, NC_PARAMTYPE_CONST);
249     if(rpc == 0) {
250         log_error("could not create rpc");
251         free(content);
252         return NTS_ERR_FAILED;
253     }
254     
255     msg_id = 0;
256     send_ret = nc_send_rpc(client->session, rpc, timeout, &msg_id);
257     if(send_ret != NC_MSG_RPC) {
258         log_error("could not send rpc");
259         free(content);
260         nc_rpc_free(rpc);
261         return NTS_ERR_FAILED;
262     }
263
264     reply_ret = nc_recv_reply(client->session, rpc, msg_id, timeout, LYD_OPT_DESTRUCT | LYD_OPT_NOSIBLINGS, &reply);
265     if((reply_ret != NC_MSG_REPLY) || (reply->type != NC_RPL_OK)) {
266         log_error("could not get rpc reply");
267
268         free(content);
269         nc_rpc_free(rpc);
270         return NTS_ERR_FAILED;
271     }
272     
273     free(content);
274     nc_reply_free(reply);
275     nc_rpc_free(rpc);
276
277     return NTS_ERR_OK;
278 }
279
280 int nc_client_set_item_str(nc_client_t *client, const char *xpath, const char *value) {
281     assert(client);
282     assert(xpath);
283     assert(value);
284
285     if(client->edit_batch_root) {
286         struct lyd_node *n = lyd_new_path(client->edit_batch_root, 0, xpath, (void*)value, LYD_ANYDATA_CONSTSTRING, 0);
287         if(n == 0) {
288             log_error("lyd_new_path error");
289             return NTS_ERR_FAILED;
290         }
291     }
292     else {
293         client->edit_batch_root = lyd_new_path(0, session_context, xpath, (void*)value, LYD_ANYDATA_CONSTSTRING, 0);
294         if(client->edit_batch_root == 0) {
295             log_error("lyd_new_path error");
296             return NTS_ERR_FAILED;
297         }
298     }
299
300     return NTS_ERR_OK;
301 }
302
303 int nc_client_edit_apply_changes(nc_client_t *client, int timeout) {
304     assert(client);
305     assert(client->edit_batch_root);
306
307     int rc = nc_client_edit_batch(client, client->edit_batch_root, timeout);
308     lyd_free_withsiblings(client->edit_batch_root);
309     client->edit_batch_root = 0;
310     return rc;
311 }
312
313 int lyd_utils_dup(sr_session_ctx_t *session, const char *xpath_s, const char *xpath_d, struct lyd_node **tree) {
314     assert(session);
315     assert(xpath_s);
316     assert(xpath_d);
317     assert(tree);
318
319     if(*tree == 0) {
320         *tree = lyd_new_path(0, session_context, xpath_d, 0, LYD_ANYDATA_CONSTSTRING, 0);
321         if(*tree == 0) {
322             return NTS_ERR_FAILED;
323         }
324     }
325
326     struct lyd_node *data_s = 0;
327     int rc = sr_get_data(session, xpath_s, 0, 0, 0, &data_s);
328     if(rc != SR_ERR_OK) {
329         log_error("could not get value for xPath=%s from the datastore\n", xpath_s);
330         lyd_free(*tree);
331         return NTS_ERR_FAILED;
332     }
333
334     struct lyd_node *next = 0;
335     struct lyd_node *snode = 0;
336     LY_TREE_DFS_BEGIN(data_s, next, snode) {
337         char *xpath_c = lyd_path(snode);
338         if((snode->schema->nodetype == LYS_LEAF) || (snode->schema->nodetype == LYS_LEAFLIST)) {
339             const char *value = ((struct lyd_node_leaf_list*)snode)->value_str;
340             char *new_xpath = str_replace(xpath_c, xpath_s, xpath_d);
341             
342             ly_log_options(0);
343             lyd_new_path(*tree, 0, new_xpath, (void*)value, LYD_ANYDATA_CONSTSTRING, 0);
344             free(xpath_c);
345             free(new_xpath);
346         }
347         LY_TREE_DFS_END(data_s, next, snode);
348     }
349
350     lyd_free(data_s);
351     return NTS_ERR_OK;
352 }