blob: e904cb8fb16ca9156d2425e5f72e2c7b3da69d1a [file] [log] [blame]
Michal Vasko086311b2016-01-08 09:53:11 +01001/**
2 * \file session_server.c
3 * \author Michal Vasko <mvasko@cesnet.cz>
4 * \brief libnetconf2 server session manipulation functions
5 *
6 * Copyright (c) 2015 CESNET, z.s.p.o.
7 *
Radek Krejci9b81f5b2016-02-24 13:14:49 +01008 * 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
Michal Vaskoafd416b2016-02-25 14:51:46 +010011 *
Radek Krejci9b81f5b2016-02-24 13:14:49 +010012 * https://opensource.org/licenses/BSD-3-Clause
Michal Vasko086311b2016-01-08 09:53:11 +010013 */
14
15#include <stdint.h>
16#include <stdlib.h>
17#include <errno.h>
18#include <string.h>
19#include <poll.h>
20#include <sys/types.h>
21#include <sys/socket.h>
22#include <netinet/in.h>
23#include <arpa/inet.h>
24#include <unistd.h>
Michal Vaskob48aa812016-01-18 14:13:09 +010025#include <pthread.h>
Michal Vasko11d142a2016-01-19 15:58:24 +010026#include <time.h>
Michal Vasko086311b2016-01-08 09:53:11 +010027
Michal Vasko1a38c862016-01-15 15:50:07 +010028#include "libnetconf.h"
Michal Vasko086311b2016-01-08 09:53:11 +010029#include "session_server.h"
30
Michal Vaskob48aa812016-01-18 14:13:09 +010031struct nc_server_opts server_opts = {
Michal Vasko3031aae2016-01-27 16:07:18 +010032 .endpt_array_lock = PTHREAD_RWLOCK_INITIALIZER
Michal Vaskob48aa812016-01-18 14:13:09 +010033};
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +010034
Michal Vasko3031aae2016-01-27 16:07:18 +010035extern struct nc_server_ssh_opts ssh_ch_opts;
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +010036extern pthread_mutex_t ssh_ch_opts_lock;
37
Michal Vasko3031aae2016-01-27 16:07:18 +010038extern struct nc_server_tls_opts tls_ch_opts;
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +010039extern pthread_mutex_t tls_ch_opts_lock;
Michal Vasko3031aae2016-01-27 16:07:18 +010040
41struct nc_endpt *
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +010042nc_server_endpt_lock(const char *name, NC_TRANSPORT_IMPL ti)
Michal Vasko3031aae2016-01-27 16:07:18 +010043{
44 uint16_t i;
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +010045 struct nc_endpt *endpt = NULL;
46
47 /* READ LOCK */
48 pthread_rwlock_rdlock(&server_opts.endpt_array_lock);
Michal Vasko3031aae2016-01-27 16:07:18 +010049
50 for (i = 0; i < server_opts.endpt_count; ++i) {
51 if ((server_opts.binds[i].ti == ti) && !strcmp(server_opts.endpts[i].name, name)) {
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +010052 endpt = &server_opts.endpts[i];
53 break;
Michal Vasko3031aae2016-01-27 16:07:18 +010054 }
55 }
56
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +010057 if (!endpt) {
58 ERR("Endpoint \"%s\" was not found.", name);
59 /* READ UNLOCK */
60 pthread_rwlock_unlock(&server_opts.endpt_array_lock);
61 return NULL;
62 }
63
64 /* ENDPT LOCK */
65 pthread_mutex_lock(&endpt->endpt_lock);
66
67 return endpt;
68}
69
70void
71nc_server_endpt_unlock(struct nc_endpt *endpt)
72{
73 /* ENDPT UNLOCK */
74 pthread_mutex_unlock(&endpt->endpt_lock);
75
76 /* READ UNLOCK */
Michal Vasko27562ad2016-02-02 15:50:39 +010077 pthread_rwlock_unlock(&server_opts.endpt_array_lock);
Michal Vasko3031aae2016-01-27 16:07:18 +010078}
Michal Vasko086311b2016-01-08 09:53:11 +010079
Michal Vasko1a38c862016-01-15 15:50:07 +010080API void
81nc_session_set_term_reason(struct nc_session *session, NC_SESSION_TERM_REASON reason)
82{
83 if (!session || !reason) {
84 ERRARG;
85 return;
86 }
87
88 session->term_reason = reason;
89}
90
Michal Vasko086311b2016-01-08 09:53:11 +010091int
Michal Vaskof05562c2016-01-20 12:06:43 +010092nc_sock_listen(const char *address, uint16_t port)
Michal Vasko086311b2016-01-08 09:53:11 +010093{
94 const int optVal = 1;
95 const socklen_t optLen = sizeof(optVal);
96 int is_ipv4, sock;
97 struct sockaddr_storage saddr;
98
99 struct sockaddr_in *saddr4;
100 struct sockaddr_in6 *saddr6;
101
102
103 if (!strchr(address, ':')) {
104 is_ipv4 = 1;
105 } else {
106 is_ipv4 = 0;
107 }
108
109 sock = socket((is_ipv4 ? AF_INET : AF_INET6), SOCK_STREAM, 0);
110 if (sock == -1) {
Michal Vaskod083db62016-01-19 10:31:29 +0100111 ERR("Failed to create socket (%s).", strerror(errno));
Michal Vasko086311b2016-01-08 09:53:11 +0100112 goto fail;
113 }
114
115 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *)&optVal, optLen)) {
Michal Vaskod083db62016-01-19 10:31:29 +0100116 ERR("Could not set socket SO_REUSEADDR socket option (%s).", strerror(errno));
Michal Vasko086311b2016-01-08 09:53:11 +0100117 goto fail;
118 }
119
120 bzero(&saddr, sizeof(struct sockaddr_storage));
121 if (is_ipv4) {
122 saddr4 = (struct sockaddr_in *)&saddr;
123
124 saddr4->sin_family = AF_INET;
125 saddr4->sin_port = htons(port);
126
127 if (inet_pton(AF_INET, address, &saddr4->sin_addr) != 1) {
Michal Vaskod083db62016-01-19 10:31:29 +0100128 ERR("Failed to convert IPv4 address \"%s\".", address);
Michal Vasko086311b2016-01-08 09:53:11 +0100129 goto fail;
130 }
131
132 if (bind(sock, (struct sockaddr *)saddr4, sizeof(struct sockaddr_in)) == -1) {
Michal Vaskod083db62016-01-19 10:31:29 +0100133 ERR("Could not bind \"%s\" port %d (%s).", address, port, strerror(errno));
Michal Vasko086311b2016-01-08 09:53:11 +0100134 goto fail;
135 }
136
137 } else {
138 saddr6 = (struct sockaddr_in6 *)&saddr;
139
140 saddr6->sin6_family = AF_INET6;
141 saddr6->sin6_port = htons(port);
142
143 if (inet_pton(AF_INET6, address, &saddr6->sin6_addr) != 1) {
Michal Vaskod083db62016-01-19 10:31:29 +0100144 ERR("Failed to convert IPv6 address \"%s\".", address);
Michal Vasko086311b2016-01-08 09:53:11 +0100145 goto fail;
146 }
147
148 if (bind(sock, (struct sockaddr *)saddr6, sizeof(struct sockaddr_in6)) == -1) {
Michal Vaskod083db62016-01-19 10:31:29 +0100149 ERR("Could not bind \"%s\" port %d (%s).", address, port, strerror(errno));
Michal Vasko086311b2016-01-08 09:53:11 +0100150 goto fail;
151 }
152 }
153
Michal Vaskofb89d772016-01-08 12:25:35 +0100154 if (listen(sock, NC_REVERSE_QUEUE) == -1) {
Michal Vaskod083db62016-01-19 10:31:29 +0100155 ERR("Unable to start listening on \"%s\" port %d (%s).", address, port, strerror(errno));
Michal Vasko086311b2016-01-08 09:53:11 +0100156 goto fail;
157 }
158
159 return sock;
160
161fail:
162 if (sock > -1) {
163 close(sock);
164 }
165
166 return -1;
167}
168
169int
Michal Vasko3031aae2016-01-27 16:07:18 +0100170nc_sock_accept_binds(struct nc_bind *binds, uint16_t bind_count, int timeout, char **host, uint16_t *port, uint16_t *idx)
Michal Vasko086311b2016-01-08 09:53:11 +0100171{
172 uint16_t i;
173 struct pollfd *pfd;
174 struct sockaddr_storage saddr;
175 socklen_t saddr_len = sizeof(saddr);
176 int ret, sock = -1;
177
178 pfd = malloc(bind_count * sizeof *pfd);
179 for (i = 0; i < bind_count; ++i) {
180 pfd[i].fd = binds[i].sock;
181 pfd[i].events = POLLIN;
182 pfd[i].revents = 0;
183 }
184
185 /* poll for a new connection */
186 errno = 0;
187 ret = poll(pfd, bind_count, timeout);
188 if (!ret) {
189 /* we timeouted */
190 free(pfd);
191 return 0;
192 } else if (ret == -1) {
Michal Vaskod083db62016-01-19 10:31:29 +0100193 ERR("Poll failed (%s).", strerror(errno));
Michal Vasko086311b2016-01-08 09:53:11 +0100194 free(pfd);
195 return -1;
196 }
197
198 for (i = 0; i < bind_count; ++i) {
199 if (pfd[i].revents & POLLIN) {
200 sock = pfd[i].fd;
201 break;
202 }
203 }
204 free(pfd);
205
206 if (sock == -1) {
Michal Vaskod083db62016-01-19 10:31:29 +0100207 ERRINT;
Michal Vasko086311b2016-01-08 09:53:11 +0100208 return -1;
209 }
210
211 ret = accept(sock, (struct sockaddr *)&saddr, &saddr_len);
Michal Vasko3f6cc4a2016-01-21 15:58:53 +0100212 if (ret < 0) {
Michal Vaskod083db62016-01-19 10:31:29 +0100213 ERR("Accept failed (%s).", strerror(errno));
Michal Vasko086311b2016-01-08 09:53:11 +0100214 return -1;
215 }
216
Michal Vasko3031aae2016-01-27 16:07:18 +0100217 if (idx) {
218 *idx = i;
Michal Vasko9e036d52016-01-08 10:49:26 +0100219 }
220
Michal Vasko086311b2016-01-08 09:53:11 +0100221 /* host was requested */
222 if (host) {
223 if (saddr.ss_family == AF_INET) {
224 *host = malloc(15);
225 if (!inet_ntop(AF_INET, &((struct sockaddr_in *)&saddr)->sin_addr.s_addr, *host, 15)) {
Michal Vaskod083db62016-01-19 10:31:29 +0100226 ERR("inet_ntop failed (%s).", strerror(errno));
Michal Vasko086311b2016-01-08 09:53:11 +0100227 free(*host);
228 *host = NULL;
229 }
230
231 if (port) {
232 *port = ntohs(((struct sockaddr_in *)&saddr)->sin_port);
233 }
234 } else if (saddr.ss_family == AF_INET6) {
235 *host = malloc(40);
236 if (!inet_ntop(AF_INET6, ((struct sockaddr_in6 *)&saddr)->sin6_addr.s6_addr, *host, 40)) {
Michal Vaskod083db62016-01-19 10:31:29 +0100237 ERR("inet_ntop failed (%s).", strerror(errno));
Michal Vasko086311b2016-01-08 09:53:11 +0100238 free(*host);
239 *host = NULL;
240 }
241
242 if (port) {
243 *port = ntohs(((struct sockaddr_in6 *)&saddr)->sin6_port);
244 }
245 } else {
Michal Vaskod083db62016-01-19 10:31:29 +0100246 ERR("Source host of an unknown protocol family.");
Michal Vasko086311b2016-01-08 09:53:11 +0100247 }
248 }
249
250 return ret;
251}
252
Michal Vasko05ba9df2016-01-13 14:40:27 +0100253static struct nc_server_reply *
Michal Vasko428087d2016-01-14 16:04:28 +0100254nc_clb_default_get_schema(struct lyd_node *rpc, struct nc_session *UNUSED(session))
Michal Vasko05ba9df2016-01-13 14:40:27 +0100255{
256 const char *identifier = NULL, *version = NULL, *format = NULL;
257 char *model_data = NULL;
258 const struct lys_module *module;
259 struct nc_server_error *err;
260 struct lyd_node *child, *data = NULL;
Michal Vasko11d142a2016-01-19 15:58:24 +0100261 const struct lys_node *sdata = NULL;
Michal Vasko05ba9df2016-01-13 14:40:27 +0100262
263 LY_TREE_FOR(rpc->child, child) {
264 if (!strcmp(child->schema->name, "identifier")) {
265 identifier = ((struct lyd_node_leaf_list *)child)->value_str;
266 } else if (!strcmp(child->schema->name, "version")) {
267 version = ((struct lyd_node_leaf_list *)child)->value_str;
268 } else if (!strcmp(child->schema->name, "format")) {
269 format = ((struct lyd_node_leaf_list *)child)->value_str;
270 }
271 }
272
273 /* check version */
274 if (version && (strlen(version) != 10) && strcmp(version, "1.0")) {
Michal Vasko1a38c862016-01-15 15:50:07 +0100275 err = nc_err(NC_ERR_INVALID_VALUE, NC_ERR_TYPE_APP);
276 nc_err_set_msg(err, "The requested version is not supported.", "en");
277 return nc_server_reply_err(err);
Michal Vasko05ba9df2016-01-13 14:40:27 +0100278 }
279
280 /* check and get module with the name identifier */
281 module = ly_ctx_get_module(server_opts.ctx, identifier, version);
282 if (!module) {
Michal Vasko1a38c862016-01-15 15:50:07 +0100283 err = nc_err(NC_ERR_INVALID_VALUE, NC_ERR_TYPE_APP);
284 nc_err_set_msg(err, "The requested schema was not found.", "en");
285 return nc_server_reply_err(err);
Michal Vasko05ba9df2016-01-13 14:40:27 +0100286 }
287
288 /* check format */
289 if (!format || !strcmp(format, "yang")) {
290 lys_print_mem(&model_data, module, LYS_OUT_YANG, NULL);
291 } else if (!strcmp(format, "yin")) {
292 lys_print_mem(&model_data, module, LYS_OUT_YIN, NULL);
293 } else {
Michal Vasko1a38c862016-01-15 15:50:07 +0100294 err = nc_err(NC_ERR_INVALID_VALUE, NC_ERR_TYPE_APP);
295 nc_err_set_msg(err, "The requested format is not supported.", "en");
296 return nc_server_reply_err(err);
Michal Vasko05ba9df2016-01-13 14:40:27 +0100297 }
298
Michal Vaskofea54dc2016-02-17 13:12:16 +0100299 sdata = ly_ctx_get_node(server_opts.ctx, "/ietf-netconf-monitoring:get-schema/output/data");
Michal Vasko0473c4c2016-01-19 10:40:06 +0100300 if (model_data && sdata) {
Michal Vasko05ba9df2016-01-13 14:40:27 +0100301 data = lyd_output_new_anyxml(sdata, model_data);
302 }
303 free(model_data);
304 if (!data) {
305 ERRINT;
306 return NULL;
307 }
308
309 return nc_server_reply_data(data, NC_PARAMTYPE_FREE);
310}
311
312static struct nc_server_reply *
Michal Vasko428087d2016-01-14 16:04:28 +0100313nc_clb_default_close_session(struct lyd_node *UNUSED(rpc), struct nc_session *session)
Michal Vasko05ba9df2016-01-13 14:40:27 +0100314{
Michal Vasko428087d2016-01-14 16:04:28 +0100315 session->term_reason = NC_SESSION_TERM_CLOSED;
316 return nc_server_reply_ok();
Michal Vasko05ba9df2016-01-13 14:40:27 +0100317}
318
Michal Vasko086311b2016-01-08 09:53:11 +0100319API int
320nc_server_init(struct ly_ctx *ctx)
321{
Michal Vasko05ba9df2016-01-13 14:40:27 +0100322 const struct lys_node *rpc;
323
Michal Vasko086311b2016-01-08 09:53:11 +0100324 if (!ctx) {
325 ERRARG;
326 return -1;
327 }
328
Michal Vasko05ba9df2016-01-13 14:40:27 +0100329 /* set default <get-schema> callback if not specified */
Michal Vaskofea54dc2016-02-17 13:12:16 +0100330 rpc = ly_ctx_get_node(ctx, "/ietf-netconf-monitoring:get-schema");
Michal Vasko05ba9df2016-01-13 14:40:27 +0100331 if (rpc && !rpc->private) {
332 lys_set_private(rpc, nc_clb_default_get_schema);
333 }
334
335 /* set default <close-session> callback if not specififed */
Michal Vaskofea54dc2016-02-17 13:12:16 +0100336 rpc = ly_ctx_get_node(ctx, "/ietf-netconf:close-session");
Michal Vasko05ba9df2016-01-13 14:40:27 +0100337 if (rpc && !rpc->private) {
338 lys_set_private(rpc, nc_clb_default_close_session);
339 }
340
Michal Vasko086311b2016-01-08 09:53:11 +0100341 server_opts.ctx = ctx;
Michal Vaskob48aa812016-01-18 14:13:09 +0100342
343 server_opts.new_session_id = 1;
344 pthread_spin_init(&server_opts.sid_lock, PTHREAD_PROCESS_PRIVATE);
345
Michal Vasko086311b2016-01-08 09:53:11 +0100346 return 0;
347}
348
Michal Vaskob48aa812016-01-18 14:13:09 +0100349API void
350nc_server_destroy(void)
351{
352 pthread_spin_destroy(&server_opts.sid_lock);
353
Radek Krejci53691be2016-02-22 13:58:37 +0100354#if defined(NC_ENABLED_SSH) || defined(NC_ENABLED_TLS)
Michal Vasko3031aae2016-01-27 16:07:18 +0100355 nc_server_del_endpt(NULL, 0);
Michal Vaskob48aa812016-01-18 14:13:09 +0100356#endif
357}
358
Michal Vasko086311b2016-01-08 09:53:11 +0100359API int
360nc_server_set_capab_withdefaults(NC_WD_MODE basic_mode, int also_supported)
361{
362 if (!basic_mode || (basic_mode == NC_WD_ALL_TAG)
363 || (also_supported && !(also_supported & (NC_WD_ALL | NC_WD_ALL_TAG | NC_WD_TRIM | NC_WD_EXPLICIT)))) {
364 ERRARG;
365 return -1;
366 }
367
368 server_opts.wd_basic_mode = basic_mode;
369 server_opts.wd_also_supported = also_supported;
370 return 0;
371}
372
Michal Vasko1a38c862016-01-15 15:50:07 +0100373API void
Michal Vasko086311b2016-01-08 09:53:11 +0100374nc_server_set_capab_interleave(int interleave_support)
375{
376 if (interleave_support) {
377 server_opts.interleave_capab = 1;
378 } else {
379 server_opts.interleave_capab = 0;
380 }
Michal Vasko086311b2016-01-08 09:53:11 +0100381}
382
Michal Vasko1a38c862016-01-15 15:50:07 +0100383API void
Michal Vasko086311b2016-01-08 09:53:11 +0100384nc_server_set_hello_timeout(uint16_t hello_timeout)
385{
Michal Vasko086311b2016-01-08 09:53:11 +0100386 server_opts.hello_timeout = hello_timeout;
Michal Vasko086311b2016-01-08 09:53:11 +0100387}
388
Michal Vasko1a38c862016-01-15 15:50:07 +0100389API void
Michal Vasko086311b2016-01-08 09:53:11 +0100390nc_server_set_idle_timeout(uint16_t idle_timeout)
391{
Michal Vasko086311b2016-01-08 09:53:11 +0100392 server_opts.idle_timeout = idle_timeout;
Michal Vasko086311b2016-01-08 09:53:11 +0100393}
394
395API int
Michal Vasko1a38c862016-01-15 15:50:07 +0100396nc_accept_inout(int fdin, int fdout, const char *username, struct nc_session **session)
Michal Vasko086311b2016-01-08 09:53:11 +0100397{
Michal Vasko7f1c78b2016-01-19 09:52:14 +0100398 if (!server_opts.ctx || (fdin < 0) || (fdout < 0) || !username || !session) {
Michal Vasko1a38c862016-01-15 15:50:07 +0100399 ERRARG;
400 return -1;
Michal Vasko086311b2016-01-08 09:53:11 +0100401 }
402
403 /* prepare session structure */
Michal Vasko1a38c862016-01-15 15:50:07 +0100404 *session = calloc(1, sizeof **session);
405 if (!(*session)) {
Michal Vasko086311b2016-01-08 09:53:11 +0100406 ERRMEM;
Michal Vasko1a38c862016-01-15 15:50:07 +0100407 return -1;
Michal Vasko086311b2016-01-08 09:53:11 +0100408 }
Michal Vasko1a38c862016-01-15 15:50:07 +0100409 (*session)->status = NC_STATUS_STARTING;
410 (*session)->side = NC_SERVER;
Michal Vasko086311b2016-01-08 09:53:11 +0100411
412 /* transport specific data */
Michal Vasko1a38c862016-01-15 15:50:07 +0100413 (*session)->ti_type = NC_TI_FD;
414 (*session)->ti.fd.in = fdin;
415 (*session)->ti.fd.out = fdout;
Michal Vasko086311b2016-01-08 09:53:11 +0100416
417 /* assign context (dicionary needed for handshake) */
Michal Vasko1a38c862016-01-15 15:50:07 +0100418 (*session)->flags = NC_SESSION_SHAREDCTX;
419 (*session)->ctx = server_opts.ctx;
Michal Vasko086311b2016-01-08 09:53:11 +0100420
Michal Vaskob48aa812016-01-18 14:13:09 +0100421 /* assign new SID atomically */
422 pthread_spin_lock(&server_opts.sid_lock);
423 (*session)->id = server_opts.new_session_id++;
424 pthread_spin_unlock(&server_opts.sid_lock);
425
Michal Vasko086311b2016-01-08 09:53:11 +0100426 /* NETCONF handshake */
Michal Vasko1a38c862016-01-15 15:50:07 +0100427 if (nc_handshake(*session)) {
Michal Vasko086311b2016-01-08 09:53:11 +0100428 goto fail;
429 }
Michal Vasko1a38c862016-01-15 15:50:07 +0100430 (*session)->status = NC_STATUS_RUNNING;
Michal Vasko5e6f4cc2016-01-20 13:27:44 +0100431 (*session)->last_rpc = time(NULL);
Michal Vasko086311b2016-01-08 09:53:11 +0100432
Michal Vasko1a38c862016-01-15 15:50:07 +0100433 return 0;
Michal Vasko086311b2016-01-08 09:53:11 +0100434
435fail:
Michal Vasko1a38c862016-01-15 15:50:07 +0100436 nc_session_free(*session);
437 *session = NULL;
438 return -1;
Michal Vasko086311b2016-01-08 09:53:11 +0100439}
Michal Vasko9e036d52016-01-08 10:49:26 +0100440
Michal Vasko428087d2016-01-14 16:04:28 +0100441API struct nc_pollsession *
442nc_ps_new(void)
443{
Michal Vasko48a63ed2016-03-01 09:48:21 +0100444 struct nc_pollsession *ps;
445
446 ps = calloc(1, sizeof(struct nc_pollsession));
447 pthread_mutex_init(&ps->lock, NULL);
448
449 return ps;
Michal Vasko428087d2016-01-14 16:04:28 +0100450}
451
452API void
453nc_ps_free(struct nc_pollsession *ps)
454{
Michal Vasko7f1c78b2016-01-19 09:52:14 +0100455 if (!ps) {
456 return;
457 }
458
Michal Vasko3a715132016-01-21 15:40:31 +0100459 free(ps->pfds);
Michal Vasko428087d2016-01-14 16:04:28 +0100460 free(ps->sessions);
Michal Vasko48a63ed2016-03-01 09:48:21 +0100461 pthread_mutex_destroy(&ps->lock);
462
Michal Vasko428087d2016-01-14 16:04:28 +0100463 free(ps);
464}
465
466API int
467nc_ps_add_session(struct nc_pollsession *ps, struct nc_session *session)
468{
469 if (!ps || !session) {
470 ERRARG;
471 return -1;
472 }
473
Michal Vasko48a63ed2016-03-01 09:48:21 +0100474 /* LOCK */
475 pthread_mutex_lock(&ps->lock);
476
Michal Vasko428087d2016-01-14 16:04:28 +0100477 ++ps->session_count;
Michal Vasko3a715132016-01-21 15:40:31 +0100478 ps->pfds = realloc(ps->pfds, ps->session_count * sizeof *ps->pfds);
Michal Vasko428087d2016-01-14 16:04:28 +0100479 ps->sessions = realloc(ps->sessions, ps->session_count * sizeof *ps->sessions);
480
481 switch (session->ti_type) {
482 case NC_TI_FD:
Michal Vasko3a715132016-01-21 15:40:31 +0100483 ps->pfds[ps->session_count - 1].fd = session->ti.fd.in;
Michal Vasko428087d2016-01-14 16:04:28 +0100484 break;
485
Radek Krejci53691be2016-02-22 13:58:37 +0100486#ifdef NC_ENABLED_SSH
Michal Vasko428087d2016-01-14 16:04:28 +0100487 case NC_TI_LIBSSH:
Michal Vasko3a715132016-01-21 15:40:31 +0100488 ps->pfds[ps->session_count - 1].fd = ssh_get_fd(session->ti.libssh.session);
Michal Vasko428087d2016-01-14 16:04:28 +0100489 break;
490#endif
491
Radek Krejci53691be2016-02-22 13:58:37 +0100492#ifdef NC_ENABLED_TLS
Michal Vasko428087d2016-01-14 16:04:28 +0100493 case NC_TI_OPENSSL:
Michal Vasko3a715132016-01-21 15:40:31 +0100494 ps->pfds[ps->session_count - 1].fd = SSL_get_rfd(session->ti.tls);
Michal Vasko428087d2016-01-14 16:04:28 +0100495 break;
496#endif
497
498 default:
499 ERRINT;
Michal Vasko48a63ed2016-03-01 09:48:21 +0100500 /* UNLOCK */
501 pthread_mutex_unlock(&ps->lock);
Michal Vasko428087d2016-01-14 16:04:28 +0100502 return -1;
503 }
Michal Vasko3a715132016-01-21 15:40:31 +0100504 ps->pfds[ps->session_count - 1].events = POLLIN;
505 ps->pfds[ps->session_count - 1].revents = 0;
506 ps->sessions[ps->session_count - 1] = session;
Michal Vasko428087d2016-01-14 16:04:28 +0100507
Michal Vasko48a63ed2016-03-01 09:48:21 +0100508 /* UNLOCK */
509 pthread_mutex_unlock(&ps->lock);
510
Michal Vasko428087d2016-01-14 16:04:28 +0100511 return 0;
512}
513
Michal Vasko48a63ed2016-03-01 09:48:21 +0100514static int
515_nc_ps_del_session(struct nc_pollsession *ps, struct nc_session *session)
Michal Vasko428087d2016-01-14 16:04:28 +0100516{
517 uint16_t i;
518
Michal Vasko428087d2016-01-14 16:04:28 +0100519 for (i = 0; i < ps->session_count; ++i) {
Michal Vasko3a715132016-01-21 15:40:31 +0100520 if (ps->sessions[i] == session) {
Michal Vasko428087d2016-01-14 16:04:28 +0100521 --ps->session_count;
Michal Vasko58005732016-02-02 15:50:52 +0100522 if (i < ps->session_count) {
523 ps->sessions[i] = ps->sessions[ps->session_count];
524 memcpy(&ps->pfds[i], &ps->pfds[ps->session_count], sizeof *ps->pfds);
525 } else if (!ps->session_count) {
526 free(ps->sessions);
527 ps->sessions = NULL;
528 free(ps->pfds);
529 ps->pfds = NULL;
530 }
Michal Vasko428087d2016-01-14 16:04:28 +0100531 return 0;
532 }
533 }
534
Michal Vaskof0537d82016-01-29 14:42:38 +0100535 return -1;
Michal Vasko428087d2016-01-14 16:04:28 +0100536}
537
Michal Vasko48a63ed2016-03-01 09:48:21 +0100538API int
539nc_ps_del_session(struct nc_pollsession *ps, struct nc_session *session)
540{
541 int ret;
542
543 if (!ps || !session) {
544 ERRARG;
545 return -1;
546 }
547
548 /* LOCK */
549 pthread_mutex_lock(&ps->lock);
550
551 ret = _nc_ps_del_session(ps, session);
552
553 /* UNLOCK */
554 pthread_mutex_unlock(&ps->lock);
555
556 return ret;
557}
558
Michal Vasko0fdb7ac2016-03-01 09:03:12 +0100559API uint16_t
560nc_ps_session_count(struct nc_pollsession *ps)
561{
Michal Vasko48a63ed2016-03-01 09:48:21 +0100562 uint16_t count;
563
Michal Vasko0fdb7ac2016-03-01 09:03:12 +0100564 if (!ps) {
565 ERRARG;
566 return 0;
567 }
568
Michal Vasko48a63ed2016-03-01 09:48:21 +0100569 /* LOCK */
570 pthread_mutex_lock(&ps->lock);
571
572 count = ps->session_count;
573
574 /* UNLOCK */
575 pthread_mutex_unlock(&ps->lock);
576
577 return count;
Michal Vasko0fdb7ac2016-03-01 09:03:12 +0100578}
579
Michal Vasko428087d2016-01-14 16:04:28 +0100580/* must be called holding the session lock! */
581static NC_MSG_TYPE
582nc_recv_rpc(struct nc_session *session, struct nc_server_rpc **rpc)
583{
584 struct lyxml_elem *xml = NULL;
585 NC_MSG_TYPE msgtype;
586
587 if (!session || !rpc) {
588 ERRARG;
589 return NC_MSG_ERROR;
590 } else if ((session->status != NC_STATUS_RUNNING) || (session->side != NC_SERVER)) {
Michal Vaskod083db62016-01-19 10:31:29 +0100591 ERR("Session %u: invalid session to receive RPCs.", session->id);
Michal Vasko428087d2016-01-14 16:04:28 +0100592 return NC_MSG_ERROR;
593 }
594
595 msgtype = nc_read_msg(session, &xml);
596
597 switch (msgtype) {
598 case NC_MSG_RPC:
599 *rpc = malloc(sizeof **rpc);
Michal Vaskoca4a2422016-02-02 12:17:14 +0100600
Michal Vasko428087d2016-01-14 16:04:28 +0100601 (*rpc)->tree = lyd_parse_xml(server_opts.ctx, &xml->child, LYD_OPT_DESTRUCT | LYD_OPT_RPC);
Michal Vaskoca4a2422016-02-02 12:17:14 +0100602 if (!(*rpc)->tree) {
603 ERR("Session %u: received message failed to be parsed into a known RPC.", session->id);
604 msgtype = NC_MSG_NONE;
605 }
Michal Vasko428087d2016-01-14 16:04:28 +0100606 (*rpc)->root = xml;
607 break;
608 case NC_MSG_HELLO:
Michal Vaskod083db62016-01-19 10:31:29 +0100609 ERR("Session %u: received another <hello> message.", session->id);
Michal Vasko428087d2016-01-14 16:04:28 +0100610 goto error;
611 case NC_MSG_REPLY:
Michal Vasko81614ee2016-02-02 12:20:14 +0100612 ERR("Session %u: received <rpc-reply> from a NETCONF client.", session->id);
Michal Vasko428087d2016-01-14 16:04:28 +0100613 goto error;
614 case NC_MSG_NOTIF:
Michal Vasko81614ee2016-02-02 12:20:14 +0100615 ERR("Session %u: received <notification> from a NETCONF client.", session->id);
Michal Vasko428087d2016-01-14 16:04:28 +0100616 goto error;
617 default:
618 /* NC_MSG_ERROR - pass it out;
619 * NC_MSG_WOULDBLOCK and NC_MSG_NONE is not returned by nc_read_msg()
620 */
621 break;
622 }
623
624 return msgtype;
625
626error:
627 /* cleanup */
628 lyxml_free(server_opts.ctx, xml);
629
630 return NC_MSG_ERROR;
631}
632
633/* must be called holding the session lock! */
634static NC_MSG_TYPE
635nc_send_reply(struct nc_session *session, struct nc_server_rpc *rpc)
636{
637 nc_rpc_clb clb;
638 struct nc_server_reply *reply;
639 int ret;
640
641 /* no callback, reply with a not-implemented error */
Michal Vaskoca4a2422016-02-02 12:17:14 +0100642 if (!rpc->tree || !rpc->tree->schema->private) {
Michal Vasko1a38c862016-01-15 15:50:07 +0100643 reply = nc_server_reply_err(nc_err(NC_ERR_OP_NOT_SUPPORTED, NC_ERR_TYPE_PROT));
Michal Vasko428087d2016-01-14 16:04:28 +0100644 } else {
645 clb = (nc_rpc_clb)rpc->tree->schema->private;
646 reply = clb(rpc->tree, session);
647 }
648
649 if (!reply) {
Michal Vasko1a38c862016-01-15 15:50:07 +0100650 reply = nc_server_reply_err(nc_err(NC_ERR_OP_FAILED, NC_ERR_TYPE_APP));
Michal Vasko428087d2016-01-14 16:04:28 +0100651 }
652
653 ret = nc_write_msg(session, NC_MSG_REPLY, rpc->root, reply);
654
655 /* special case if term_reason was set in callback, last reply was sent (needed for <close-session> if nothing else) */
656 if ((session->status == NC_STATUS_RUNNING) && (session->term_reason != NC_SESSION_TERM_NONE)) {
657 session->status = NC_STATUS_INVALID;
658 }
659
660 if (ret == -1) {
Michal Vaskod083db62016-01-19 10:31:29 +0100661 ERR("Session %u: failed to write reply.", session->id);
Michal Vasko428087d2016-01-14 16:04:28 +0100662 nc_server_reply_free(reply);
663 return NC_MSG_ERROR;
664 }
665 nc_server_reply_free(reply);
666
667 return NC_MSG_REPLY;
668}
669
670API int
671nc_ps_poll(struct nc_pollsession *ps, int timeout)
672{
673 int ret;
Michal Vasko3512e402016-01-28 16:22:34 +0100674 uint16_t i;
Michal Vasko5e6f4cc2016-01-20 13:27:44 +0100675 time_t cur_time;
Michal Vasko428087d2016-01-14 16:04:28 +0100676 NC_MSG_TYPE msgtype;
677 struct nc_session *session;
678 struct nc_server_rpc *rpc;
Michal Vasko428087d2016-01-14 16:04:28 +0100679
680 if (!ps || !ps->session_count) {
681 ERRARG;
682 return -1;
683 }
684
Michal Vasko5e6f4cc2016-01-20 13:27:44 +0100685 cur_time = time(NULL);
686
Michal Vasko48a63ed2016-03-01 09:48:21 +0100687 /* LOCK */
688 pthread_mutex_lock(&ps->lock);
689
Michal Vasko428087d2016-01-14 16:04:28 +0100690 for (i = 0; i < ps->session_count; ++i) {
Michal Vasko3a715132016-01-21 15:40:31 +0100691 if (ps->sessions[i]->status != NC_STATUS_RUNNING) {
692 ERR("Session %u: session not running.", ps->sessions[i]->id);
Michal Vasko48a63ed2016-03-01 09:48:21 +0100693 ret = -1;
694 goto finish;
Michal Vasko428087d2016-01-14 16:04:28 +0100695 }
Michal Vaskobd8ef262016-01-20 11:09:27 +0100696
Michal Vasko5e6f4cc2016-01-20 13:27:44 +0100697 /* TODO invalidate only sessions without subscription */
Michal Vasko3a715132016-01-21 15:40:31 +0100698 if (server_opts.idle_timeout && (ps->sessions[i]->last_rpc + server_opts.idle_timeout >= cur_time)) {
699 ERR("Session %u: session idle timeout elapsed.", ps->sessions[i]->id);
700 ps->sessions[i]->status = NC_STATUS_INVALID;
701 ps->sessions[i]->term_reason = NC_SESSION_TERM_TIMEOUT;
Michal Vasko48a63ed2016-03-01 09:48:21 +0100702 ret = 3;
703 goto finish;
Michal Vasko5e6f4cc2016-01-20 13:27:44 +0100704 }
705
Michal Vasko3a715132016-01-21 15:40:31 +0100706 if (ps->pfds[i].revents) {
Michal Vaskobd8ef262016-01-20 11:09:27 +0100707 break;
708 }
Michal Vasko428087d2016-01-14 16:04:28 +0100709 }
710
Michal Vaskobd8ef262016-01-20 11:09:27 +0100711 if (i == ps->session_count) {
Radek Krejci53691be2016-02-22 13:58:37 +0100712#ifdef NC_ENABLED_SSH
Michal Vasko3a715132016-01-21 15:40:31 +0100713retry_poll:
Michal Vasko3512e402016-01-28 16:22:34 +0100714#endif
Michal Vaskobd8ef262016-01-20 11:09:27 +0100715 /* no leftover event */
716 i = 0;
Michal Vasko3a715132016-01-21 15:40:31 +0100717 ret = poll(ps->pfds, ps->session_count, timeout);
Michal Vaskobd8ef262016-01-20 11:09:27 +0100718 if (ret < 1) {
Michal Vasko48a63ed2016-03-01 09:48:21 +0100719 goto finish;
Michal Vaskobd8ef262016-01-20 11:09:27 +0100720 }
Michal Vasko428087d2016-01-14 16:04:28 +0100721 }
722
Michal Vaskobd8ef262016-01-20 11:09:27 +0100723 /* find the first fd with POLLIN, we don't care if there are more now */
724 for (; i < ps->session_count; ++i) {
Michal Vasko3a715132016-01-21 15:40:31 +0100725 if (ps->pfds[i].revents & POLLHUP) {
726 ERR("Session %u: communication socket unexpectedly closed.", ps->sessions[i]->id);
727 ps->sessions[i]->status = NC_STATUS_INVALID;
728 ps->sessions[i]->term_reason = NC_SESSION_TERM_DROPPED;
Michal Vasko48a63ed2016-03-01 09:48:21 +0100729 ret = 3;
730 goto finish;
Michal Vasko3a715132016-01-21 15:40:31 +0100731 } else if (ps->pfds[i].revents & POLLERR) {
732 ERR("Session %u: communication socket error.", ps->sessions[i]->id);
733 ps->sessions[i]->status = NC_STATUS_INVALID;
734 ps->sessions[i]->term_reason = NC_SESSION_TERM_OTHER;
Michal Vasko48a63ed2016-03-01 09:48:21 +0100735 ret = 3;
736 goto finish;
Michal Vasko3a715132016-01-21 15:40:31 +0100737 } else if (ps->pfds[i].revents & POLLIN) {
Radek Krejci53691be2016-02-22 13:58:37 +0100738#ifdef NC_ENABLED_SSH
Michal Vasko96164bf2016-01-21 15:41:58 +0100739 if (ps->sessions[i]->ti_type == NC_TI_LIBSSH) {
Michal Vasko3512e402016-01-28 16:22:34 +0100740 uint16_t j;
741
Michal Vasko96164bf2016-01-21 15:41:58 +0100742 /* things are not that simple with SSH... */
743 ret = nc_ssh_pollin(ps->sessions[i], &timeout);
744
745 /* clear POLLIN on sessions sharing this session's SSH session */
746 if ((ret == 1) || (ret >= 4)) {
747 for (j = i + 1; j < ps->session_count; ++j) {
748 if (ps->pfds[j].fd == ps->pfds[i].fd) {
749 ps->pfds[j].revents = 0;
750 }
751 }
752 }
753
754 /* actual event happened */
755 if ((ret <= 0) || (ret >= 3)) {
756 ps->pfds[i].revents = 0;
Michal Vasko48a63ed2016-03-01 09:48:21 +0100757 goto finish;
Michal Vasko96164bf2016-01-21 15:41:58 +0100758
759 /* event occurred on some other channel */
760 } else if (ret == 2) {
761 ps->pfds[i].revents = 0;
Michal Vasko428087d2016-01-14 16:04:28 +0100762 if (i == ps->session_count - 1) {
763 /* last session and it is not the right channel, ... */
Michal Vasko8c748832016-02-03 15:32:16 +0100764 if (!timeout) {
Michal Vasko428087d2016-01-14 16:04:28 +0100765 /* ... timeout is 0, so that is it */
Michal Vasko48a63ed2016-03-01 09:48:21 +0100766 ret = 0;
767 goto finish;
Michal Vasko428087d2016-01-14 16:04:28 +0100768 }
Michal Vasko8c748832016-02-03 15:32:16 +0100769 /* ... retry polling reasonable time apart ... */
770 usleep(NC_TIMEOUT_STEP);
771 if (timeout > 0) {
772 /* ... and decrease timeout, if not -1 */
Michal Vasko7b38e232016-02-26 15:01:07 +0100773 timeout -= NC_TIMEOUT_STEP * 1000;
Michal Vasko8c748832016-02-03 15:32:16 +0100774 }
775 goto retry_poll;
Michal Vasko428087d2016-01-14 16:04:28 +0100776 }
777 /* check other sessions */
778 continue;
Michal Vasko428087d2016-01-14 16:04:28 +0100779 }
780 }
Radek Krejci53691be2016-02-22 13:58:37 +0100781#endif /* NC_ENABLED_SSH */
Michal Vasko428087d2016-01-14 16:04:28 +0100782
Michal Vaskobd8ef262016-01-20 11:09:27 +0100783 /* we are going to process it now */
Michal Vasko3a715132016-01-21 15:40:31 +0100784 ps->pfds[i].revents = 0;
Michal Vasko428087d2016-01-14 16:04:28 +0100785 break;
786 }
787 }
788
789 if (i == ps->session_count) {
790 ERRINT;
Michal Vasko48a63ed2016-03-01 09:48:21 +0100791 ret = -1;
792 goto finish;
Michal Vasko428087d2016-01-14 16:04:28 +0100793 }
794
795 /* this is the session with some data available for reading */
Michal Vasko3a715132016-01-21 15:40:31 +0100796 session = ps->sessions[i];
Michal Vasko428087d2016-01-14 16:04:28 +0100797
Michal Vaskobd8ef262016-01-20 11:09:27 +0100798 /* reading an RPC and sending a reply must be atomic (no other RPC should be read) */
Michal Vasko7f1c78b2016-01-19 09:52:14 +0100799 ret = nc_timedlock(session->ti_lock, timeout, NULL);
800 if (ret != 1) {
801 /* error or timeout */
Michal Vasko48a63ed2016-03-01 09:48:21 +0100802 goto finish;
Michal Vasko428087d2016-01-14 16:04:28 +0100803 }
804
805 msgtype = nc_recv_rpc(session, &rpc);
806 if (msgtype == NC_MSG_ERROR) {
Michal Vasko7f1c78b2016-01-19 09:52:14 +0100807 pthread_mutex_unlock(session->ti_lock);
Michal Vasko428087d2016-01-14 16:04:28 +0100808 if (session->status != NC_STATUS_RUNNING) {
Michal Vasko48a63ed2016-03-01 09:48:21 +0100809 ret = 3;
810 goto finish;
Michal Vasko428087d2016-01-14 16:04:28 +0100811 }
Michal Vasko48a63ed2016-03-01 09:48:21 +0100812 ret = -1;
813 goto finish;
Michal Vasko428087d2016-01-14 16:04:28 +0100814 }
815
Michal Vaskoca4a2422016-02-02 12:17:14 +0100816 /* NC_MSG_NONE is not a real (known) RPC */
817 if (msgtype == NC_MSG_RPC) {
818 session->last_rpc = time(NULL);
819 }
820
Michal Vasko428087d2016-01-14 16:04:28 +0100821 /* process RPC */
822 msgtype = nc_send_reply(session, rpc);
823
Michal Vasko7f1c78b2016-01-19 09:52:14 +0100824 pthread_mutex_unlock(session->ti_lock);
Michal Vasko428087d2016-01-14 16:04:28 +0100825
826 if (msgtype == NC_MSG_ERROR) {
Michal Vaskoca4a2422016-02-02 12:17:14 +0100827 nc_server_rpc_free(rpc, server_opts.ctx);
Michal Vasko48a63ed2016-03-01 09:48:21 +0100828 ret = -1;
829 goto finish;
Michal Vasko428087d2016-01-14 16:04:28 +0100830 }
Michal Vaskoca4a2422016-02-02 12:17:14 +0100831 nc_server_rpc_free(rpc, server_opts.ctx);
Michal Vaskobd8ef262016-01-20 11:09:27 +0100832
Michal Vaskobd8b4e12016-01-22 16:11:20 +0100833 /* status change takes precedence over leftover events (return 2) */
834 if (session->status != NC_STATUS_RUNNING) {
Michal Vasko48a63ed2016-03-01 09:48:21 +0100835 ret = 3;
836 goto finish;
Michal Vaskobd8b4e12016-01-22 16:11:20 +0100837 }
838
Michal Vaskobd8ef262016-01-20 11:09:27 +0100839 /* is there some other socket waiting? */
840 for (++i; i < ps->session_count; ++i) {
Michal Vasko3a715132016-01-21 15:40:31 +0100841 if (ps->pfds[i].revents) {
Michal Vasko48a63ed2016-03-01 09:48:21 +0100842 ret = 2;
843 goto finish;
Michal Vaskobd8ef262016-01-20 11:09:27 +0100844 }
845 }
846
Michal Vasko48a63ed2016-03-01 09:48:21 +0100847 ret = 1;
848
849finish:
850 /* UNLOCK */
851 pthread_mutex_unlock(&ps->lock);
852 return ret;
Michal Vasko428087d2016-01-14 16:04:28 +0100853}
854
Michal Vaskod09eae62016-02-01 10:32:52 +0100855API void
Michal Vaskocad3ac42016-03-01 09:06:01 +0100856nc_ps_clear(struct nc_pollsession *ps, int all)
Michal Vaskod09eae62016-02-01 10:32:52 +0100857{
858 uint16_t i;
859 struct nc_session *session;
860
Michal Vasko9a25e932016-02-01 10:36:42 +0100861 if (!ps) {
862 ERRARG;
863 return;
864 }
865
Michal Vasko48a63ed2016-03-01 09:48:21 +0100866 /* LOCK */
867 pthread_mutex_lock(&ps->lock);
Michal Vaskod09eae62016-02-01 10:32:52 +0100868
Michal Vasko48a63ed2016-03-01 09:48:21 +0100869 if (all) {
870 for (i = 0; i < ps->session_count; ) {
871 nc_session_free(ps->sessions[i]);
872 }
873 free(ps->sessions);
874 ps->sessions = NULL;
875 free(ps->pfds);
876 ps->pfds = NULL;
877 ps->session_count = 0;
878 } else {
879 for (i = 0; i < ps->session_count; ) {
880 if (ps->sessions[i]->status != NC_STATUS_RUNNING) {
881 session = ps->sessions[i];
882 _nc_ps_del_session(ps, session);
883 nc_session_free(session);
884 continue;
885 }
886
887 ++i;
888 }
Michal Vaskod09eae62016-02-01 10:32:52 +0100889 }
Michal Vasko48a63ed2016-03-01 09:48:21 +0100890
891 /* UNLOCK */
892 pthread_mutex_unlock(&ps->lock);
Michal Vaskod09eae62016-02-01 10:32:52 +0100893}
894
Radek Krejci53691be2016-02-22 13:58:37 +0100895#if defined(NC_ENABLED_SSH) || defined(NC_ENABLED_TLS)
Michal Vasko9e036d52016-01-08 10:49:26 +0100896
Michal Vasko3031aae2016-01-27 16:07:18 +0100897int
898nc_server_add_endpt_listen(const char *name, const char *address, uint16_t port, NC_TRANSPORT_IMPL ti)
Michal Vasko9e036d52016-01-08 10:49:26 +0100899{
900 int sock;
Michal Vasko3031aae2016-01-27 16:07:18 +0100901 uint16_t i;
Radek Krejci53691be2016-02-22 13:58:37 +0100902#ifdef NC_ENABLED_SSH
Michal Vasko08a629a2016-02-02 12:20:47 +0100903 struct nc_server_ssh_opts *ssh_opts;
904#endif
Michal Vasko9e036d52016-01-08 10:49:26 +0100905
Michal Vasko3031aae2016-01-27 16:07:18 +0100906 if (!name || !address || !port) {
Michal Vasko9e036d52016-01-08 10:49:26 +0100907 ERRARG;
908 return -1;
909 }
910
Michal Vasko51e514d2016-02-02 15:51:52 +0100911 /* WRITE LOCK */
912 pthread_rwlock_wrlock(&server_opts.endpt_array_lock);
Michal Vasko3031aae2016-01-27 16:07:18 +0100913
914 /* check name uniqueness */
915 for (i = 0; i < server_opts.endpt_count; ++i) {
Michal Vaskod4c03a82016-02-08 15:27:26 +0100916 if ((server_opts.binds[i].ti == ti) && !strcmp(server_opts.endpts[i].name, name)) {
Michal Vasko3031aae2016-01-27 16:07:18 +0100917 ERR("Endpoint \"%s\" already exists.", name);
Michal Vasko51e514d2016-02-02 15:51:52 +0100918 /* WRITE UNLOCK */
Michal Vasko9faf1c82016-02-01 13:26:19 +0100919 pthread_rwlock_unlock(&server_opts.endpt_array_lock);
Michal Vasko3031aae2016-01-27 16:07:18 +0100920 return -1;
921 }
922 }
923
Michal Vasko9e036d52016-01-08 10:49:26 +0100924 sock = nc_sock_listen(address, port);
925 if (sock == -1) {
Michal Vasko51e514d2016-02-02 15:51:52 +0100926 /* WRITE UNLOCK */
927 pthread_rwlock_unlock(&server_opts.endpt_array_lock);
Michal Vasko9e036d52016-01-08 10:49:26 +0100928 return -1;
929 }
930
Michal Vasko3031aae2016-01-27 16:07:18 +0100931 ++server_opts.endpt_count;
932 server_opts.binds = realloc(server_opts.binds, server_opts.endpt_count * sizeof *server_opts.binds);
933 server_opts.endpts = realloc(server_opts.endpts, server_opts.endpt_count * sizeof *server_opts.endpts);
Michal Vasko9e036d52016-01-08 10:49:26 +0100934
Michal Vasko3031aae2016-01-27 16:07:18 +0100935 server_opts.endpts[server_opts.endpt_count - 1].name = lydict_insert(server_opts.ctx, name, 0);
936 server_opts.binds[server_opts.endpt_count - 1].address = lydict_insert(server_opts.ctx, address, 0);
Michal Vasko3031aae2016-01-27 16:07:18 +0100937 server_opts.binds[server_opts.endpt_count - 1].port = port;
938 server_opts.binds[server_opts.endpt_count - 1].sock = sock;
939 server_opts.binds[server_opts.endpt_count - 1].ti = ti;
940 switch (ti) {
Radek Krejci53691be2016-02-22 13:58:37 +0100941#ifdef NC_ENABLED_SSH
Michal Vasko3031aae2016-01-27 16:07:18 +0100942 case NC_TI_LIBSSH:
Michal Vasko08a629a2016-02-02 12:20:47 +0100943 ssh_opts = calloc(1, sizeof *ssh_opts);
944 /* set default values */
945 ssh_opts->auth_methods = NC_SSH_AUTH_PUBLICKEY | NC_SSH_AUTH_PASSWORD | NC_SSH_AUTH_INTERACTIVE;
946 ssh_opts->auth_attempts = 3;
947 ssh_opts->auth_timeout = 10;
948
949 server_opts.endpts[server_opts.endpt_count - 1].ti_opts = ssh_opts;
Michal Vasko3031aae2016-01-27 16:07:18 +0100950 break;
951#endif
Radek Krejci53691be2016-02-22 13:58:37 +0100952#ifdef NC_ENABLED_TLS
Michal Vasko3031aae2016-01-27 16:07:18 +0100953 case NC_TI_OPENSSL:
954 server_opts.endpts[server_opts.endpt_count - 1].ti_opts = calloc(1, sizeof(struct nc_server_tls_opts));
955 break;
956#endif
957 default:
958 ERRINT;
959 server_opts.endpts[server_opts.endpt_count - 1].ti_opts = NULL;
960 break;
961 }
962 pthread_mutex_init(&server_opts.endpts[server_opts.endpt_count - 1].endpt_lock, NULL);
Michal Vasko9e036d52016-01-08 10:49:26 +0100963
Michal Vasko3031aae2016-01-27 16:07:18 +0100964 /* WRITE UNLOCK */
965 pthread_rwlock_unlock(&server_opts.endpt_array_lock);
Michal Vaskob48aa812016-01-18 14:13:09 +0100966
Michal Vasko9e036d52016-01-08 10:49:26 +0100967 return 0;
968}
969
Michal Vasko3031aae2016-01-27 16:07:18 +0100970int
Michal Vaskoda514772016-02-01 11:32:01 +0100971nc_server_endpt_set_address_port(const char *endpt_name, const char *address, uint16_t port, NC_TRANSPORT_IMPL ti)
972{
973 struct nc_endpt *endpt;
974 struct nc_bind *bind = NULL;
975 uint16_t i;
976 int sock;
977
978 if (!endpt_name || (!address && !port) || (address && port) || !ti) {
979 ERRARG;
980 return -1;
981 }
982
Michal Vasko51e514d2016-02-02 15:51:52 +0100983 /* LOCK */
Michal Vaskoda514772016-02-01 11:32:01 +0100984 endpt = nc_server_endpt_lock(endpt_name, ti);
985 if (!endpt) {
986 return -1;
987 }
988
989 /* we need to learn the index, to get the bind :-/ */
990 for (i = 0; i < server_opts.endpt_count; ++i) {
991 if (&server_opts.endpts[i] == endpt) {
992 bind = &server_opts.binds[i];
993 }
994 }
995 if (!bind) {
996 ERRINT;
Michal Vasko51e514d2016-02-02 15:51:52 +0100997 goto fail;
Michal Vaskoda514772016-02-01 11:32:01 +0100998 }
999
1000 if (address) {
1001 sock = nc_sock_listen(address, bind->port);
1002 } else {
1003 sock = nc_sock_listen(bind->address, port);
1004 }
1005 if (sock == -1) {
Michal Vasko51e514d2016-02-02 15:51:52 +01001006 goto fail;
Michal Vaskoda514772016-02-01 11:32:01 +01001007 }
1008
1009 /* close old socket, update parameters */
1010 close(bind->sock);
1011 bind->sock = sock;
1012 if (address) {
1013 lydict_remove(server_opts.ctx, bind->address);
1014 bind->address = lydict_insert(server_opts.ctx, address, 0);
1015 } else {
1016 bind->port = port;
1017 }
1018
Michal Vasko51e514d2016-02-02 15:51:52 +01001019 /* UNLOCK */
Michal Vasko7a93af72016-02-01 16:00:15 +01001020 nc_server_endpt_unlock(endpt);
Michal Vaskoda514772016-02-01 11:32:01 +01001021 return 0;
Michal Vasko51e514d2016-02-02 15:51:52 +01001022
1023fail:
1024 /* UNLOCK */
1025 nc_server_endpt_unlock(endpt);
1026 return -1;
Michal Vaskoda514772016-02-01 11:32:01 +01001027}
1028
1029int
Michal Vasko3031aae2016-01-27 16:07:18 +01001030nc_server_del_endpt(const char *name, NC_TRANSPORT_IMPL ti)
Michal Vasko9e036d52016-01-08 10:49:26 +01001031{
1032 uint32_t i;
1033 int ret = -1;
1034
Michal Vasko3031aae2016-01-27 16:07:18 +01001035 /* WRITE LOCK */
1036 pthread_rwlock_wrlock(&server_opts.endpt_array_lock);
Michal Vaskob48aa812016-01-18 14:13:09 +01001037
Michal Vasko3031aae2016-01-27 16:07:18 +01001038 if (!name && !ti) {
1039 /* remove all */
Michal Vasko3031aae2016-01-27 16:07:18 +01001040 for (i = 0; i < server_opts.endpt_count; ++i) {
1041 lydict_remove(server_opts.ctx, server_opts.endpts[i].name);
Michal Vasko11d142a2016-01-19 15:58:24 +01001042 lydict_remove(server_opts.ctx, server_opts.binds[i].address);
Michal Vasko51e514d2016-02-02 15:51:52 +01001043
Michal Vasko3031aae2016-01-27 16:07:18 +01001044 close(server_opts.binds[i].sock);
1045 pthread_mutex_destroy(&server_opts.endpts[i].endpt_lock);
1046 switch (server_opts.binds[i].ti) {
Radek Krejci53691be2016-02-22 13:58:37 +01001047#ifdef NC_ENABLED_SSH
Michal Vasko3031aae2016-01-27 16:07:18 +01001048 case NC_TI_LIBSSH:
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +01001049 nc_server_ssh_clear_opts(server_opts.endpts[i].ti_opts);
Michal Vasko3031aae2016-01-27 16:07:18 +01001050 break;
1051#endif
Radek Krejci53691be2016-02-22 13:58:37 +01001052#ifdef NC_ENABLED_TLS
Michal Vasko3031aae2016-01-27 16:07:18 +01001053 case NC_TI_OPENSSL:
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +01001054 nc_server_tls_clear_opts(server_opts.endpts[i].ti_opts);
Michal Vasko3031aae2016-01-27 16:07:18 +01001055 break;
1056#endif
1057 default:
1058 ERRINT;
1059 break;
1060 }
1061 free(server_opts.endpts[i].ti_opts);
Michal Vasko9e036d52016-01-08 10:49:26 +01001062
Michal Vasko9e036d52016-01-08 10:49:26 +01001063 ret = 0;
1064 }
Michal Vasko7ddc5702016-02-08 15:29:39 +01001065 free(server_opts.binds);
1066 server_opts.binds = NULL;
Michal Vasko3031aae2016-01-27 16:07:18 +01001067 free(server_opts.endpts);
1068 server_opts.endpts = NULL;
1069 server_opts.endpt_count = 0;
1070
Michal Vasko1a38c862016-01-15 15:50:07 +01001071 } else {
Michal Vasko3031aae2016-01-27 16:07:18 +01001072 /* remove one name endpoint or all ti endpoints */
1073 for (i = 0; i < server_opts.endpt_count; ++i) {
1074 if ((server_opts.binds[i].ti == ti) &&
1075 (!name || !strcmp(server_opts.endpts[i].name, name))) {
1076
Michal Vasko3031aae2016-01-27 16:07:18 +01001077 lydict_remove(server_opts.ctx, server_opts.endpts[i].name);
Michal Vasko11d142a2016-01-19 15:58:24 +01001078 lydict_remove(server_opts.ctx, server_opts.binds[i].address);
Michal Vasko3031aae2016-01-27 16:07:18 +01001079 close(server_opts.binds[i].sock);
1080 pthread_mutex_destroy(&server_opts.endpts[i].endpt_lock);
1081 switch (server_opts.binds[i].ti) {
Radek Krejci53691be2016-02-22 13:58:37 +01001082#ifdef NC_ENABLED_SSH
Michal Vasko3031aae2016-01-27 16:07:18 +01001083 case NC_TI_LIBSSH:
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +01001084 nc_server_ssh_clear_opts(server_opts.endpts[i].ti_opts);
Michal Vasko3031aae2016-01-27 16:07:18 +01001085 break;
1086#endif
Radek Krejci53691be2016-02-22 13:58:37 +01001087#ifdef NC_ENABLED_TLS
Michal Vasko3031aae2016-01-27 16:07:18 +01001088 case NC_TI_OPENSSL:
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +01001089 nc_server_tls_clear_opts(server_opts.endpts[i].ti_opts);
Michal Vasko3031aae2016-01-27 16:07:18 +01001090 break;
1091#endif
1092 default:
1093 ERRINT;
1094 break;
1095 }
1096 free(server_opts.endpts[i].ti_opts);
Michal Vasko1a38c862016-01-15 15:50:07 +01001097
Michal Vasko3031aae2016-01-27 16:07:18 +01001098 --server_opts.endpt_count;
Michal Vaskoc0256492016-02-02 12:19:06 +01001099 if (i < server_opts.endpt_count) {
1100 memcpy(&server_opts.binds[i], &server_opts.binds[server_opts.endpt_count], sizeof *server_opts.binds);
1101 memcpy(&server_opts.endpts[i], &server_opts.endpts[server_opts.endpt_count], sizeof *server_opts.endpts);
1102 } else if (!server_opts.endpt_count) {
1103 free(server_opts.binds);
1104 server_opts.binds = NULL;
1105 free(server_opts.endpts);
1106 server_opts.endpts = NULL;
1107 }
Michal Vasko1a38c862016-01-15 15:50:07 +01001108
1109 ret = 0;
Michal Vasko3031aae2016-01-27 16:07:18 +01001110
1111 if (name) {
1112 /* one name endpoint removed, they are unique, we're done */
1113 break;
1114 }
Michal Vasko1a38c862016-01-15 15:50:07 +01001115 }
1116 }
Michal Vasko9e036d52016-01-08 10:49:26 +01001117 }
1118
Michal Vasko3031aae2016-01-27 16:07:18 +01001119 /* WRITE UNLOCK */
1120 pthread_rwlock_unlock(&server_opts.endpt_array_lock);
Michal Vaskob48aa812016-01-18 14:13:09 +01001121
Michal Vasko9e036d52016-01-08 10:49:26 +01001122 return ret;
1123}
1124
Michal Vasko1a38c862016-01-15 15:50:07 +01001125API int
1126nc_accept(int timeout, struct nc_session **session)
Michal Vasko9e036d52016-01-08 10:49:26 +01001127{
Michal Vasko1a38c862016-01-15 15:50:07 +01001128 int sock, ret;
Michal Vasko5c2f7952016-01-22 13:16:31 +01001129 char *host = NULL;
Michal Vasko3031aae2016-01-27 16:07:18 +01001130 uint16_t port, idx;
Michal Vasko9e036d52016-01-08 10:49:26 +01001131
Michal Vasko51e514d2016-02-02 15:51:52 +01001132 if (!server_opts.ctx || !session) {
Michal Vasko9e036d52016-01-08 10:49:26 +01001133 ERRARG;
Michal Vasko1a38c862016-01-15 15:50:07 +01001134 return -1;
Michal Vasko9e036d52016-01-08 10:49:26 +01001135 }
1136
Michal Vasko51e514d2016-02-02 15:51:52 +01001137 /* we have to hold WRITE for the whole time, since there is not
1138 * a way of downgrading the lock to READ */
1139 /* WRITE LOCK */
1140 pthread_rwlock_wrlock(&server_opts.endpt_array_lock);
1141
1142 if (!server_opts.endpt_count) {
1143 ERRARG;
1144 /* WRITE UNLOCK */
1145 pthread_rwlock_unlock(&server_opts.endpt_array_lock);
1146 return -1;
1147 }
Michal Vaskob48aa812016-01-18 14:13:09 +01001148
Michal Vasko3031aae2016-01-27 16:07:18 +01001149 ret = nc_sock_accept_binds(server_opts.binds, server_opts.endpt_count, timeout, &host, &port, &idx);
Michal Vaskob48aa812016-01-18 14:13:09 +01001150
Michal Vasko50456e82016-02-02 12:16:08 +01001151 if (ret < 1) {
Michal Vasko51e514d2016-02-02 15:51:52 +01001152 /* WRITE UNLOCK */
Michal Vasko3031aae2016-01-27 16:07:18 +01001153 pthread_rwlock_unlock(&server_opts.endpt_array_lock);
Michal Vaskob737d752016-02-09 09:01:27 +01001154 free(host);
Michal Vaskob48aa812016-01-18 14:13:09 +01001155 return ret;
Michal Vasko9e036d52016-01-08 10:49:26 +01001156 }
Michal Vaskob48aa812016-01-18 14:13:09 +01001157 sock = ret;
Michal Vasko9e036d52016-01-08 10:49:26 +01001158
Michal Vasko1a38c862016-01-15 15:50:07 +01001159 *session = calloc(1, sizeof **session);
Michal Vasko686aa312016-01-21 15:58:18 +01001160 if (!(*session)) {
Michal Vasko9e036d52016-01-08 10:49:26 +01001161 ERRMEM;
Michal Vaskoc14e3c82016-01-11 16:14:30 +01001162 close(sock);
Michal Vasko5c2f7952016-01-22 13:16:31 +01001163 free(host);
Michal Vasko3031aae2016-01-27 16:07:18 +01001164 ret = -1;
1165 goto fail;
Michal Vasko9e036d52016-01-08 10:49:26 +01001166 }
Michal Vasko1a38c862016-01-15 15:50:07 +01001167 (*session)->status = NC_STATUS_STARTING;
1168 (*session)->side = NC_SERVER;
1169 (*session)->ctx = server_opts.ctx;
1170 (*session)->flags = NC_SESSION_SHAREDCTX;
1171 (*session)->host = lydict_insert_zc(server_opts.ctx, host);
1172 (*session)->port = port;
Michal Vasko9e036d52016-01-08 10:49:26 +01001173
1174 /* transport lock */
Michal Vasko1a38c862016-01-15 15:50:07 +01001175 (*session)->ti_lock = malloc(sizeof *(*session)->ti_lock);
1176 if (!(*session)->ti_lock) {
Michal Vasko9e036d52016-01-08 10:49:26 +01001177 ERRMEM;
Michal Vaskoc14e3c82016-01-11 16:14:30 +01001178 close(sock);
Michal Vasko1a38c862016-01-15 15:50:07 +01001179 ret = -1;
Michal Vasko9e036d52016-01-08 10:49:26 +01001180 goto fail;
1181 }
Michal Vasko1a38c862016-01-15 15:50:07 +01001182 pthread_mutex_init((*session)->ti_lock, NULL);
Michal Vasko9e036d52016-01-08 10:49:26 +01001183
Michal Vasko2cc4c682016-03-01 09:16:48 +01001184 (*session)->data = server_opts.endpts[idx].ti_opts;
Michal Vasko3031aae2016-01-27 16:07:18 +01001185
Michal Vaskoc14e3c82016-01-11 16:14:30 +01001186 /* sock gets assigned to session or closed */
Radek Krejci53691be2016-02-22 13:58:37 +01001187#ifdef NC_ENABLED_SSH
Michal Vasko3031aae2016-01-27 16:07:18 +01001188 if (server_opts.binds[idx].ti == NC_TI_LIBSSH) {
Michal Vasko8f5270d2016-02-29 16:22:25 +01001189 ret = nc_accept_ssh_session(*session, sock);
Michal Vasko1a38c862016-01-15 15:50:07 +01001190 if (ret < 1) {
Michal Vasko9e036d52016-01-08 10:49:26 +01001191 goto fail;
1192 }
Michal Vasko3d865d22016-01-28 16:00:53 +01001193 } else
1194#endif
Radek Krejci53691be2016-02-22 13:58:37 +01001195#ifdef NC_ENABLED_TLS
Michal Vasko3d865d22016-01-28 16:00:53 +01001196 if (server_opts.binds[idx].ti == NC_TI_OPENSSL) {
Michal Vasko8f5270d2016-02-29 16:22:25 +01001197 ret = nc_accept_tls_session(*session, sock);
Michal Vasko1a38c862016-01-15 15:50:07 +01001198 if (ret < 1) {
Michal Vasko9e036d52016-01-08 10:49:26 +01001199 goto fail;
1200 }
Michal Vasko3d865d22016-01-28 16:00:53 +01001201 } else
1202#endif
1203 {
Michal Vasko9e036d52016-01-08 10:49:26 +01001204 ERRINT;
Michal Vaskoc14e3c82016-01-11 16:14:30 +01001205 close(sock);
Michal Vasko1a38c862016-01-15 15:50:07 +01001206 ret = -1;
Michal Vasko9e036d52016-01-08 10:49:26 +01001207 goto fail;
1208 }
1209
Michal Vasko2cc4c682016-03-01 09:16:48 +01001210 (*session)->data = NULL;
1211
Michal Vasko51e514d2016-02-02 15:51:52 +01001212 /* WRITE UNLOCK */
Michal Vasko3031aae2016-01-27 16:07:18 +01001213 pthread_rwlock_unlock(&server_opts.endpt_array_lock);
1214
Michal Vaskob48aa812016-01-18 14:13:09 +01001215 /* assign new SID atomically */
1216 /* LOCK */
1217 pthread_spin_lock(&server_opts.sid_lock);
1218 (*session)->id = server_opts.new_session_id++;
1219 /* UNLOCK */
1220 pthread_spin_unlock(&server_opts.sid_lock);
1221
Michal Vasko9e036d52016-01-08 10:49:26 +01001222 /* NETCONF handshake */
Michal Vasko1a38c862016-01-15 15:50:07 +01001223 if (nc_handshake(*session)) {
Michal Vasko3031aae2016-01-27 16:07:18 +01001224 nc_session_free(*session);
1225 *session = NULL;
1226 return -1;
Michal Vasko9e036d52016-01-08 10:49:26 +01001227 }
Michal Vasko1a38c862016-01-15 15:50:07 +01001228 (*session)->status = NC_STATUS_RUNNING;
Michal Vasko9e036d52016-01-08 10:49:26 +01001229
Michal Vasko1a38c862016-01-15 15:50:07 +01001230 return 1;
Michal Vasko9e036d52016-01-08 10:49:26 +01001231
1232fail:
Michal Vasko3031aae2016-01-27 16:07:18 +01001233 /* WRITE UNLOCK */
1234 pthread_rwlock_unlock(&server_opts.endpt_array_lock);
1235
Michal Vasko1a38c862016-01-15 15:50:07 +01001236 nc_session_free(*session);
1237 *session = NULL;
Michal Vaskoc61c4492016-01-25 11:13:34 +01001238 return ret;
Michal Vasko9e036d52016-01-08 10:49:26 +01001239}
1240
Michal Vasko3031aae2016-01-27 16:07:18 +01001241int
Michal Vasko8f5270d2016-02-29 16:22:25 +01001242nc_connect_callhome(const char *host, uint16_t port, NC_TRANSPORT_IMPL ti, struct nc_session **session)
Michal Vaskob05053d2016-01-22 16:12:06 +01001243{
1244 int sock, ret;
1245
Michal Vaskoc61c4492016-01-25 11:13:34 +01001246 if (!host || !port || !ti || !session) {
1247 ERRARG;
1248 return -1;
1249 }
1250
Michal Vaskob05053d2016-01-22 16:12:06 +01001251 sock = nc_sock_connect(host, port);
Michal Vaskoc61c4492016-01-25 11:13:34 +01001252 if (sock < 0) {
1253 return -1;
Michal Vaskob05053d2016-01-22 16:12:06 +01001254 }
1255
1256 *session = calloc(1, sizeof **session);
1257 if (!(*session)) {
1258 ERRMEM;
1259 close(sock);
1260 return -1;
1261 }
1262 (*session)->status = NC_STATUS_STARTING;
1263 (*session)->side = NC_SERVER;
1264 (*session)->ctx = server_opts.ctx;
1265 (*session)->flags = NC_SESSION_SHAREDCTX | NC_SESSION_CALLHOME;
Michal Vaskob05053d2016-01-22 16:12:06 +01001266 (*session)->host = lydict_insert(server_opts.ctx, host, 0);
Michal Vaskob05053d2016-01-22 16:12:06 +01001267 (*session)->port = port;
1268
1269 /* transport lock */
1270 (*session)->ti_lock = malloc(sizeof *(*session)->ti_lock);
1271 if (!(*session)->ti_lock) {
1272 ERRMEM;
1273 close(sock);
1274 ret = -1;
1275 goto fail;
1276 }
1277 pthread_mutex_init((*session)->ti_lock, NULL);
1278
1279 /* sock gets assigned to session or closed */
Radek Krejci53691be2016-02-22 13:58:37 +01001280#ifdef NC_ENABLED_SSH
Michal Vaskob05053d2016-01-22 16:12:06 +01001281 if (ti == NC_TI_LIBSSH) {
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +01001282 /* OPTS LOCK */
1283 pthread_mutex_lock(&ssh_ch_opts_lock);
1284
Michal Vasko2cc4c682016-03-01 09:16:48 +01001285 (*session)->data = &ssh_ch_opts;
Michal Vasko8f5270d2016-02-29 16:22:25 +01001286 ret = nc_accept_ssh_session(*session, sock);
Michal Vasko2cc4c682016-03-01 09:16:48 +01001287 (*session)->data = NULL;
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +01001288
1289 /* OPTS UNLOCK */
1290 pthread_mutex_unlock(&ssh_ch_opts_lock);
1291
Michal Vaskob05053d2016-01-22 16:12:06 +01001292 if (ret < 1) {
1293 goto fail;
1294 }
Michal Vasko3d865d22016-01-28 16:00:53 +01001295 } else
1296#endif
Radek Krejci53691be2016-02-22 13:58:37 +01001297#ifdef NC_ENABLED_TLS
Michal Vasko3d865d22016-01-28 16:00:53 +01001298 if (ti == NC_TI_OPENSSL) {
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +01001299 /* OPTS LOCK */
1300 pthread_mutex_lock(&tls_ch_opts_lock);
1301
Michal Vasko2cc4c682016-03-01 09:16:48 +01001302 (*session)->data = &tls_ch_opts;
Michal Vasko8f5270d2016-02-29 16:22:25 +01001303 ret = nc_accept_tls_session(*session, sock);
Michal Vasko2cc4c682016-03-01 09:16:48 +01001304 (*session)->data = NULL;
Michal Vaskoc6b9c7b2016-01-28 11:10:08 +01001305
1306 /* OPTS UNLOCK */
1307 pthread_mutex_unlock(&tls_ch_opts_lock);
1308
Michal Vaskob05053d2016-01-22 16:12:06 +01001309 if (ret < 1) {
1310 goto fail;
1311 }
Michal Vasko3d865d22016-01-28 16:00:53 +01001312 } else
1313#endif
1314 {
Michal Vaskob05053d2016-01-22 16:12:06 +01001315 ERRINT;
1316 close(sock);
1317 ret = -1;
1318 goto fail;
1319 }
1320
1321 /* assign new SID atomically */
1322 /* LOCK */
1323 pthread_spin_lock(&server_opts.sid_lock);
1324 (*session)->id = server_opts.new_session_id++;
1325 /* UNLOCK */
1326 pthread_spin_unlock(&server_opts.sid_lock);
1327
1328 /* NETCONF handshake */
1329 if (nc_handshake(*session)) {
1330 ret = -1;
1331 goto fail;
1332 }
1333 (*session)->status = NC_STATUS_RUNNING;
1334
1335 return 1;
1336
1337fail:
1338 nc_session_free(*session);
1339 *session = NULL;
Michal Vaskoc61c4492016-01-25 11:13:34 +01001340 return ret;
Michal Vaskob05053d2016-01-22 16:12:06 +01001341}
1342
Radek Krejci53691be2016-02-22 13:58:37 +01001343#endif /* NC_ENABLED_SSH || NC_ENABLED_TLS */