blob: ec7bd693328bbb0baf37c9802baf9f6dc9a6e011 [file] [log] [blame]
Radek Krejcie0854c02017-10-10 21:11:29 +02001/**
2 * @file ssh.c
3 * @author Radek Krejci <rkrejci@cesnet.cz>
4 * @brief SSH parameters management
5 *
6 * Copyright (c) 2017 CESNET, z.s.p.o.
7 *
8 * This source code is licensed under BSD 3-Clause License (the "License").
9 * You may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * https://opensource.org/licenses/BSD-3-Clause
13 */
14
15/* Python API header */
16#include <Python.h>
17
18/* standard headers */
19#include <string.h>
20
21#include <libyang/libyang.h>
Radek Krejci97211012017-10-13 16:05:45 +020022#include <libyang/swigpyrun.h>
Radek Krejcie0854c02017-10-10 21:11:29 +020023
Radek Krejcic2074282017-11-06 15:57:22 +010024#include "../src/messages_p.h"
Radek Krejcie0854c02017-10-10 21:11:29 +020025#include "netconf.h"
26#include "session.h"
27
28#define TIMEOUT_SEND 1000 /* 1 second */
29#define TIMEOUT_RECV 10000 /* 10 second */
30
31extern PyObject *libnetconf2Error;
Radek Krejci0f3499a2017-10-13 13:39:36 +020032extern PyObject *libnetconf2ReplyError;
Radek Krejcie0854c02017-10-10 21:11:29 +020033
34static struct nc_reply *
35rpc_send_recv(struct nc_session *session, struct nc_rpc *rpc)
36{
37 uint64_t msgid;
38 NC_MSG_TYPE msgtype;
39 struct nc_reply *reply;
40
41 msgtype = nc_send_rpc(session, rpc, TIMEOUT_SEND, &msgid);
42 if (msgtype == NC_MSG_ERROR) {
43 PyErr_SetString(PyExc_ConnectionError, "Failed to send a request.");
44 return NULL;
45 } else if (msgtype == NC_MSG_WOULDBLOCK) {
46 PyErr_SetString(PyExc_ConnectionError, "Sending a request timeouted.");
47 return NULL;
48 }
49
50recv_reply:
51 msgtype = nc_recv_reply(session, rpc, msgid, TIMEOUT_RECV, LYD_OPT_DESTRUCT | LYD_OPT_NOSIBLINGS, &reply);
52 if (msgtype == NC_MSG_ERROR) {
53 PyErr_SetString(PyExc_ConnectionError, "Failed to receive a reply.");
54 return NULL;
55 } else if (msgtype == NC_MSG_WOULDBLOCK) {
56 PyErr_SetString(PyExc_ConnectionError, "Receiving a reply timeouted.");
57 return NULL;
58 } else if (msgtype == NC_MSG_NOTIF) {
59 /* read again */
60 goto recv_reply;
61 } else if (msgtype == NC_MSG_REPLY_ERR_MSGID) {
62 /* unexpected message, try reading again to get the correct reply */
63 nc_reply_free(reply);
64 goto recv_reply;
65 }
66
67 return reply;
68}
69
70static PyObject *
Radek Krejci0f3499a2017-10-13 13:39:36 +020071err_reply_converter(struct nc_client_reply_error *reply)
72{
Radek Krejci97211012017-10-13 16:05:45 +020073 uint32_t i = 0;
74 ncErrObject *e;
75 PyObject *result;
Radek Krejci0f3499a2017-10-13 13:39:36 +020076
Radek Krejci97211012017-10-13 16:05:45 +020077 result = PyList_New(reply->count);
78 for (i = 0; i < reply->count; i++) {
79 e = PyObject_New(ncErrObject, &ncErrType);
80 e->ctx = reply->ctx;
81 e->err = malloc(sizeof *e->err);
82 memcpy(e->err, &reply->err[i], sizeof *e->err);
83 PyList_SET_ITEM(result, i, (PyObject*)e);
84 }
85 free(reply->err); /* pointers to the data were moved, so we are freeing just a container for the data */
Radek Krejci0f3499a2017-10-13 13:39:36 +020086 reply->err = NULL;
87
88 return (PyObject*)result;
89}
90
91#define RAISE_REPLY_ERROR(reply) PyErr_SetObject(libnetconf2ReplyError,err_reply_converter((struct nc_client_reply_error *)reply))
92
93static PyObject *
Radek Krejcie0854c02017-10-10 21:11:29 +020094process_reply_data(struct nc_reply *reply)
95{
Radek Krejci97211012017-10-13 16:05:45 +020096 PyObject *result, *data = NULL, *module;
Radek Krejcie0854c02017-10-10 21:11:29 +020097
98 /* check the type of the received reply message */
99 if (reply->type != NC_RPL_DATA) {
100 if (reply->type == NC_RPL_ERROR) {
Radek Krejci0f3499a2017-10-13 13:39:36 +0200101 RAISE_REPLY_ERROR(reply);
Radek Krejcie0854c02017-10-10 21:11:29 +0200102 } else {
103 PyErr_SetString(libnetconf2Error, "Unexpected reply received.");
104 }
Radek Krejci97211012017-10-13 16:05:45 +0200105 goto error;
Radek Krejcie0854c02017-10-10 21:11:29 +0200106 }
107
Radek Krejci97211012017-10-13 16:05:45 +0200108 //lyd_print_file(stdout, ((struct nc_reply_data*)reply)->data, LYD_XML, LYP_FORMAT);
109
Radek Krejcie0854c02017-10-10 21:11:29 +0200110 /* process the received data */
Radek Krejci97211012017-10-13 16:05:45 +0200111 data = SWIG_NewPointerObj(((struct nc_reply_data*)reply)->data, SWIG_Python_TypeQuery("lyd_node*"), 0);
112 if (!data) {
113 PyErr_SetString(libnetconf2Error, "Building Python object from data reply failed.");
114 goto error;
115 }
Radek Krejcie0854c02017-10-10 21:11:29 +0200116 ((struct nc_reply_data*)reply)->data = NULL;
Radek Krejci97211012017-10-13 16:05:45 +0200117
118 module = PyImport_ImportModule("libyang");
119 if (module == NULL) {
120 PyErr_SetString(libnetconf2Error, "Could not import libyang module");
121 goto error;
122 }
123
124 result = PyObject_CallMethod(module, "create_new_Data_Node", "(O)", data);
125 Py_DECREF(module);
126 Py_DECREF(data);
127 if (result == NULL) {
128 PyErr_SetString(libnetconf2Error, "Could not create Data_Node object.");
129 goto error;
130 }
131
Radek Krejcie0854c02017-10-10 21:11:29 +0200132 nc_reply_free(reply);
Radek Krejci97211012017-10-13 16:05:45 +0200133 return result;
Radek Krejcie0854c02017-10-10 21:11:29 +0200134
Radek Krejci97211012017-10-13 16:05:45 +0200135error:
136 Py_XDECREF(data);
137 nc_reply_free(reply);
138 return NULL;
Radek Krejcie0854c02017-10-10 21:11:29 +0200139}
140
141PyObject *
142ncRPCGet(ncSessionObject *self, PyObject *args, PyObject *keywords)
143{
144 const char *xml = NULL, *xpath = NULL;
145 static char *kwlist[] = {"subtree", "xpath", NULL};
146 struct nc_rpc *rpc;
147 struct nc_reply *reply;
148
149 if (!PyArg_ParseTupleAndKeywords(args, keywords, "|ss:ncRPCGet", kwlist, &xml, &xpath)) {
150 return NULL;
151 }
152
153 rpc = nc_rpc_get(xml ? xml : xpath, NC_WD_UNKNOWN, NC_PARAMTYPE_CONST);
154 if (!rpc) {
155 return NULL;
156 }
157
158 reply = rpc_send_recv(self->session, rpc);
159 nc_rpc_free(rpc);
160 if (!reply) {
161 return NULL;
162 }
163
164 return process_reply_data(reply);
165}
166
167PyObject *
168ncRPCGetConfig(ncSessionObject *self, PyObject *args, PyObject *keywords)
169{
170 const char *xml = NULL, *xpath = NULL;
171 static char *kwlist[] = {"datastore", "subtree", "xpath", NULL};
172 struct nc_rpc *rpc;
173 struct nc_reply *reply;
174 NC_DATASTORE datastore;
175
176 if (!PyArg_ParseTupleAndKeywords(args, keywords, "i|ss:ncRPCGetConfig", kwlist, &datastore, &xml, &xpath)) {
177 return NULL;
178 }
179
180 rpc = nc_rpc_getconfig(datastore, xml ? xml : xpath, NC_WD_UNKNOWN, NC_PARAMTYPE_CONST);
181 if (!rpc) {
182 return NULL;
183 }
184
185 reply = rpc_send_recv(self->session, rpc);
186 nc_rpc_free(rpc);
187 if (!reply) {
188 return NULL;
189 }
190
191 return process_reply_data(reply);
192}