blob: 9be866b526b5badb0e4c73bcfada60b78e743d24 [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
16#include <pthread.h>
17#include <stdio.h>
18#include <stdlib.h>
19#include <string.h>
20#include <sys/types.h>
21#include <sys/wait.h>
22#include <unistd.h>
23
24#include <libyang/libyang.h>
25
26#include <log.h>
27#include <messages_p.h>
28#include <messages_server.h>
29#include <session_client.h>
30#include <session_server.h>
31#include "tests/config.h"
32
33/* millisec */
34#define NC_ACCEPT_TIMEOUT 5000
35/* millisec */
36#define NC_PS_POLL_TIMEOUT 5000
37/* sec */
38#define CLIENT_SSH_AUTH_TIMEOUT 10
39
40#define nc_assert(cond) if (!(cond)) { fprintf(stderr, "assert failed (%s:%d)\n", __FILE__, __LINE__); exit(1); }
41
42#if _POSIX_BARRIERS >= 200112L
43pthread_barrier_t barrier;
44pthread_barrier_t barrier_msg;
45#endif
46
47typedef struct arg {
48 int in;
49 int out;
50 struct ly_ctx *ctx;
51} arg_t;
52
53struct nc_server_reply *
54rpc_clb(struct lyd_node *rpc, struct nc_session *session)
55{
56 (void)rpc; (void)session;
57 return nc_server_reply_ok();
58}
59
60static void *
61server_thread(void *arg)
62{
63 struct nc_session *sess;
64 struct nc_server_notif *notif;
65 struct lyd_node *ntf;
66 struct ly_in *in;
67 struct nc_pollsession *ps;
68 arg_t args = *(arg_t *)arg;
69 char *eventtime;
70 struct timespec ts;
71 const char *data;
72 int poll;
73
74 nc_assert(!nc_server_init(args.ctx));
75 nc_assert(nc_accept_inout(args.in, args.out, "test", &sess) == NC_MSG_HELLO);
76 nc_session_inc_notif_status(sess);
77 data =
78 "<n1 xmlns=\"n1\">\n"
79 " <first>Test</first>\n"
80 "</n1>\n";
81
82 nc_assert(ly_in_new_memory(data, &in) == LY_SUCCESS);
83 nc_assert(lyd_parse_op(args.ctx, NULL, in, LYD_XML, LYD_TYPE_NOTIF_YANG, &ntf, NULL) == LY_SUCCESS);
84 ly_in_free(in, 0);
85
86 nc_assert(clock_gettime(CLOCK_REALTIME, &ts) != -1);
87 nc_assert(ly_time_ts2str(&ts, &eventtime) == LY_SUCCESS);
88 notif = nc_server_notif_new(ntf, eventtime, NC_PARAMTYPE_FREE);
89
90 ps = nc_ps_new();
91 nc_assert(ps);
92 nc_ps_add_session(ps, sess);
93 poll = nc_ps_poll(ps, 1000, &sess);
94 nc_server_notif_send(sess, notif, 1000);
95 nc_assert(poll == NC_PSPOLL_RPC);
96 nc_ps_clear(ps, 1, NULL);
97 nc_ps_free(ps);
98
99 /* Waiting for end of test */
100 pthread_barrier_wait(&barrier);
101
102 nc_server_notif_free(notif);
103 return arg;
104}
105
106static void *
107notif_thread(void *arg)
108{
109 struct nc_session *sess = (struct nc_session *)arg;
110 struct lyd_node *envp;
111 struct lyd_node *op;
112 NC_MSG_TYPE msgtype;
113
114 /* Sync threads for receiving message to increase chance of datarace */
115 pthread_barrier_wait(&barrier_msg);
116 do {
117 msgtype = nc_recv_notif(sess, 1000, &envp, &op);
118 } while (msgtype == NC_MSG_REPLY);
119 nc_assert(msgtype == NC_MSG_NOTIF);
120 lyd_free_tree(envp);
121 lyd_free_tree(op);
122 return arg;
123}
124
125int
126main(void)
127{
128 int pipes[4];
129 struct nc_session *sess;
130 struct lyd_node *op, *envp;
131 struct ly_ctx *ctx;
132 struct nc_rpc *rpc;
133 uint64_t msgid;
134 NC_MSG_TYPE msgtype;
135 const char *features[] = {"startup", NULL};
136 arg_t thread_arg;
137 pthread_t t[2];
138
139 pthread_barrier_init(&barrier, NULL, 2);
140 pthread_barrier_init(&barrier_msg, NULL, 2);
141
142 /* Create a two pipes */
143 nc_assert(pipe(pipes) != -1);
144 nc_assert(pipe(pipes + 2) != -1);
145 thread_arg.in = pipes[0];
146 thread_arg.out = pipes[3];
147
148 /* Create context */
149 nc_assert(ly_ctx_new(TESTS_DIR "/data/modules", 0, &ctx) == LY_SUCCESS);
150 nc_assert(ly_ctx_load_module(ctx, "ietf-netconf", NULL, features));
151 nc_assert(ly_ctx_load_module(ctx, "notif1", NULL, NULL));
152 thread_arg.ctx = ctx;
153 nc_set_global_rpc_clb(rpc_clb);
154
155 /* Start server thread */
156 pthread_create(&t[0], NULL, server_thread, &thread_arg);
157 nc_client_init();
158
159 /* Listen for notifications */
160 sess = nc_connect_inout(pipes[2], pipes[1], ctx);
161 nc_assert(sess);
162 pthread_create(&t[1], NULL, notif_thread, sess);
163
164 /* Send rpc */
165 rpc = nc_rpc_delete(NC_DATASTORE_STARTUP, NULL, NC_PARAMTYPE_CONST);
166 nc_assert(nc_send_rpc(sess, rpc, 1000, &msgid) == NC_MSG_RPC);
167
168 /* Sync threads for receiving message to increase chance of datarace */
169 pthread_barrier_wait(&barrier_msg);
170 do {
171 msgtype = nc_recv_reply(sess, rpc, msgid, 1000, &envp, &op);
172 } while (msgtype == NC_MSG_NOTIF);
173 nc_assert(msgtype == NC_MSG_REPLY);
174 nc_rpc_free(rpc);
175 lyd_free_tree(envp);
176
177 /* Waiting of end of test */
178 pthread_barrier_wait(&barrier);
179 pthread_join(t[0], NULL);
180 pthread_join(t[1], NULL);
181
182 /* Cleanup */
183 nc_session_free(sess, NULL);
184 ly_ctx_destroy(ctx);
185 for (uint8_t i = 0; i < 4; i++) {
186 close(pipes[i]);
187 }
188 return 0;
189}