blob: 89eaa0233af8a1050f6f877b6f4d448a313f9bf6 [file] [log] [blame]
tadeas-vintrlik36af6962021-08-23 16:18:21 +02001/**
2 * \file test_thread_messages
3 * \author Tadeas Vintrlik <xvint04@stud.fit.vutbr.cz>
4 * \brief libnetconf2 tests - thread-safety for receiving messages
5 *
6 * Copyright 2021 Deutsche Telekom AG.
7 * Copyright 2021 CESNET, z.s.p.o.
8 *
9 * This source code is licensed under BSD 3-Clause License (the "License").
10 * You may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
12 *
13 * https://opensource.org/licenses/BSD-3-Clause
14 */
15
Michal Vaskoba9f3582023-02-22 10:26:32 +010016#define _GNU_SOURCE
17
tadeas-vintrlik36af6962021-08-23 16:18:21 +020018#include <pthread.h>
19#include <stdio.h>
20#include <stdlib.h>
21#include <string.h>
22#include <sys/types.h>
23#include <sys/wait.h>
24#include <unistd.h>
25
26#include <libyang/libyang.h>
27
28#include <log.h>
29#include <messages_p.h>
30#include <messages_server.h>
31#include <session_client.h>
32#include <session_server.h>
33#include "tests/config.h"
34
35/* millisec */
36#define NC_ACCEPT_TIMEOUT 5000
37/* millisec */
38#define NC_PS_POLL_TIMEOUT 5000
39/* sec */
40#define CLIENT_SSH_AUTH_TIMEOUT 10
41
42#define nc_assert(cond) if (!(cond)) { fprintf(stderr, "assert failed (%s:%d)\n", __FILE__, __LINE__); exit(1); }
43
44#if _POSIX_BARRIERS >= 200112L
45pthread_barrier_t barrier;
46pthread_barrier_t barrier_msg;
47#endif
48
49typedef struct arg {
50 int in;
51 int out;
52 struct ly_ctx *ctx;
53} arg_t;
54
55struct nc_server_reply *
56rpc_clb(struct lyd_node *rpc, struct nc_session *session)
57{
58 (void)rpc; (void)session;
59 return nc_server_reply_ok();
60}
61
62static void *
63server_thread(void *arg)
64{
65 struct nc_session *sess;
66 struct nc_server_notif *notif;
67 struct lyd_node *ntf;
68 struct ly_in *in;
69 struct nc_pollsession *ps;
70 arg_t args = *(arg_t *)arg;
71 char *eventtime;
72 struct timespec ts;
73 const char *data;
74 int poll;
75
Michal Vasko93224072021-11-09 12:14:28 +010076 nc_assert(!nc_server_init());
77 nc_assert(nc_accept_inout(args.in, args.out, "test", args.ctx, &sess) == NC_MSG_HELLO);
tadeas-vintrlik36af6962021-08-23 16:18:21 +020078 nc_session_inc_notif_status(sess);
79 data =
80 "<n1 xmlns=\"n1\">\n"
81 " <first>Test</first>\n"
82 "</n1>\n";
83
84 nc_assert(ly_in_new_memory(data, &in) == LY_SUCCESS);
85 nc_assert(lyd_parse_op(args.ctx, NULL, in, LYD_XML, LYD_TYPE_NOTIF_YANG, &ntf, NULL) == LY_SUCCESS);
86 ly_in_free(in, 0);
87
88 nc_assert(clock_gettime(CLOCK_REALTIME, &ts) != -1);
89 nc_assert(ly_time_ts2str(&ts, &eventtime) == LY_SUCCESS);
90 notif = nc_server_notif_new(ntf, eventtime, NC_PARAMTYPE_FREE);
91
92 ps = nc_ps_new();
93 nc_assert(ps);
94 nc_ps_add_session(ps, sess);
Michal Vasko5e32c402022-01-12 14:05:09 +010095
96 /* get for ietf-yang-library data; delete-config in test */
tadeas-vintrlik36af6962021-08-23 16:18:21 +020097 poll = nc_ps_poll(ps, 1000, &sess);
tadeas-vintrlik36af6962021-08-23 16:18:21 +020098 nc_assert(poll == NC_PSPOLL_RPC);
Michal Vasko5e32c402022-01-12 14:05:09 +010099 poll = nc_ps_poll(ps, 1000, &sess);
100 nc_assert(poll == NC_PSPOLL_RPC);
101
102 nc_server_notif_send(sess, notif, 1000);
103
tadeas-vintrlik36af6962021-08-23 16:18:21 +0200104 nc_ps_clear(ps, 1, NULL);
105 nc_ps_free(ps);
106
107 /* Waiting for end of test */
108 pthread_barrier_wait(&barrier);
109
110 nc_server_notif_free(notif);
111 return arg;
112}
113
114static void *
115notif_thread(void *arg)
116{
117 struct nc_session *sess = (struct nc_session *)arg;
118 struct lyd_node *envp;
119 struct lyd_node *op;
120 NC_MSG_TYPE msgtype;
121
122 /* Sync threads for receiving message to increase chance of datarace */
123 pthread_barrier_wait(&barrier_msg);
124 do {
125 msgtype = nc_recv_notif(sess, 1000, &envp, &op);
126 } while (msgtype == NC_MSG_REPLY);
127 nc_assert(msgtype == NC_MSG_NOTIF);
128 lyd_free_tree(envp);
129 lyd_free_tree(op);
130 return arg;
131}
132
133int
134main(void)
135{
136 int pipes[4];
137 struct nc_session *sess;
138 struct lyd_node *op, *envp;
Michal Vasko1d116a12022-02-03 15:23:20 +0100139 struct ly_ctx *server_ctx, *client_ctx;
tadeas-vintrlik36af6962021-08-23 16:18:21 +0200140 struct nc_rpc *rpc;
141 uint64_t msgid;
142 NC_MSG_TYPE msgtype;
143 const char *features[] = {"startup", NULL};
144 arg_t thread_arg;
145 pthread_t t[2];
146
147 pthread_barrier_init(&barrier, NULL, 2);
148 pthread_barrier_init(&barrier_msg, NULL, 2);
149
150 /* Create a two pipes */
151 nc_assert(pipe(pipes) != -1);
152 nc_assert(pipe(pipes + 2) != -1);
153 thread_arg.in = pipes[0];
154 thread_arg.out = pipes[3];
155
Michal Vasko1d116a12022-02-03 15:23:20 +0100156 /* Create both contexts */
157 nc_assert(ly_ctx_new(TESTS_DIR "/data/modules", 0, &server_ctx) == LY_SUCCESS);
158 nc_assert(ly_ctx_load_module(server_ctx, "ietf-netconf", NULL, features));
159 nc_assert(ly_ctx_load_module(server_ctx, "notif1", NULL, NULL));
160 thread_arg.ctx = server_ctx;
tadeas-vintrlik36af6962021-08-23 16:18:21 +0200161 nc_set_global_rpc_clb(rpc_clb);
162
Michal Vasko1d116a12022-02-03 15:23:20 +0100163 nc_assert(ly_ctx_new(TESTS_DIR "/data/modules", 0, &client_ctx) == LY_SUCCESS);
164 nc_assert(ly_ctx_load_module(client_ctx, "ietf-netconf", NULL, features));
165 nc_assert(ly_ctx_load_module(client_ctx, "notif1", NULL, NULL));
166
tadeas-vintrlik36af6962021-08-23 16:18:21 +0200167 /* Start server thread */
168 pthread_create(&t[0], NULL, server_thread, &thread_arg);
169 nc_client_init();
170
171 /* Listen for notifications */
Michal Vasko1d116a12022-02-03 15:23:20 +0100172 sess = nc_connect_inout(pipes[2], pipes[1], client_ctx);
tadeas-vintrlik36af6962021-08-23 16:18:21 +0200173 nc_assert(sess);
174 pthread_create(&t[1], NULL, notif_thread, sess);
175
176 /* Send rpc */
177 rpc = nc_rpc_delete(NC_DATASTORE_STARTUP, NULL, NC_PARAMTYPE_CONST);
178 nc_assert(nc_send_rpc(sess, rpc, 1000, &msgid) == NC_MSG_RPC);
179
180 /* Sync threads for receiving message to increase chance of datarace */
181 pthread_barrier_wait(&barrier_msg);
182 do {
183 msgtype = nc_recv_reply(sess, rpc, msgid, 1000, &envp, &op);
184 } while (msgtype == NC_MSG_NOTIF);
185 nc_assert(msgtype == NC_MSG_REPLY);
186 nc_rpc_free(rpc);
187 lyd_free_tree(envp);
188
189 /* Waiting of end of test */
190 pthread_barrier_wait(&barrier);
191 pthread_join(t[0], NULL);
192 pthread_join(t[1], NULL);
193
194 /* Cleanup */
195 nc_session_free(sess, NULL);
Michal Vasko1d116a12022-02-03 15:23:20 +0100196 ly_ctx_destroy(server_ctx);
197 ly_ctx_destroy(client_ctx);
tadeas-vintrlik36af6962021-08-23 16:18:21 +0200198 for (uint8_t i = 0; i < 4; i++) {
199 close(pipes[i]);
200 }
201 return 0;
202}