1/*
2 * Copyright (c) Crackerjack Project., 2007-2008, Hitachi, Ltd
3 * Copyright (c) 2017 Petr Vorel <pvorel@suse.cz>
4 *
5 * Authors:
6 * Takahiro Yasui <takahiro.yasui.mp@hitachi.com>,
7 * Yumiko Sugita <yumiko.sugita.yf@hitachi.com>,
8 * Satoshi Fujiwara <sa-fuji@sdl.hitachi.co.jp>
9 *
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License as
12 * published by the Free Software Foundation; either version 2 of
13 * the License, or (at your option) any later version.
14 *
15 * This program is distributed in the hope that it would be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program. If not, see <http://www.gnu.org/licenses/>.
22 */
23
24#include <errno.h>
25#include <limits.h>
26
27static int fd, fd_root, fd_nonblock, fd_maxint = INT_MAX - 1, fd_invalid = -1;
28static struct timespec ts;
29
30#include "mq_timed.h"
31
32static struct test_case tcase[] = {
33	{
34		.fd = &fd,
35		.len = 0,
36		.ret = 0,
37		.err = 0,
38	},
39	{
40		.fd = &fd,
41		.len = 1,
42		.ret = 0,
43		.err = 0,
44	},
45	{
46		.fd = &fd,
47		.len = MAX_MSGSIZE,
48		.ret = 0,
49		.err = 0,
50	},
51	{
52		.fd = &fd,
53		.len = 1,
54		.prio = MQ_PRIO_MAX - 1,
55		.ret = 0,
56		.err = 0,
57	},
58	{
59		.fd = &fd,
60		.len = MAX_MSGSIZE + 1,
61		.ret = -1,
62		.err = EMSGSIZE,
63	},
64	{
65		.fd = &fd_invalid,
66		.len = 0,
67		.ret = -1,
68		.err = EBADF,
69	},
70	{
71		.fd = &fd_maxint,
72		.len = 0,
73		.ret = -1,
74		.err = EBADF,
75	},
76	{
77		.fd = &fd_root,
78		.len = 0,
79		.ret = -1,
80		.err = EBADF,
81	},
82	{
83		.fd = &fd_nonblock,
84		.len = 16,
85		.ret = -1,
86		.err = EAGAIN,
87	},
88	{
89		.fd = &fd,
90		.len = 1,
91		.prio = MQ_PRIO_MAX,
92		.ret = -1,
93		.err = EINVAL,
94	},
95	{
96		.fd = &fd,
97		.len = 16,
98		.rq = &(struct timespec) {.tv_sec = -1, .tv_nsec = 0},
99		.send = 1,
100		.ret = -1,
101		.err = EINVAL,
102	},
103	{
104		.fd = &fd,
105		.len = 16,
106		.rq = &(struct timespec) {.tv_sec = 0, .tv_nsec = -1},
107		.send = 1,
108		.ret = -1,
109		.err = EINVAL,
110	},
111	{
112		.fd = &fd,
113		.len = 16,
114		.rq = &(struct timespec) {.tv_sec = 0, .tv_nsec = 1000000000},
115		.send = 1,
116		.ret = -1,
117		.err = EINVAL,
118	},
119	{
120		.fd = &fd,
121		.len = 16,
122		.rq = &ts,
123		.send = 1,
124		.timeout = 1,
125		.ret = -1,
126		.err = ETIMEDOUT,
127	},
128	{
129		.fd = &fd,
130		.len = 16,
131		.send = 1,
132		.signal = 1,
133		.rq = &ts,
134		.ret = -1,
135		.err = EINTR,
136	},
137};
138
139static void do_test(unsigned int i)
140{
141	const struct test_case *tc = &tcase[i];
142	unsigned int j;
143	unsigned int prio;
144	size_t len = MAX_MSGSIZE;
145	char rmsg[len];
146	pid_t pid = -1;
147
148	if (tc->signal)
149		pid = set_sig(tc->rq);
150
151	if (tc->timeout)
152		set_timeout(tc->rq);
153
154	if (tc->send) {
155		for (j = 0; j < MSG_LENGTH; j++)
156			send_msg(*tc->fd, tc->len, tc->prio);
157	}
158
159	TEST(mq_timedsend(*tc->fd, smsg, tc->len, tc->prio, tc->rq));
160
161	if (pid > 0)
162		kill_pid(pid);
163
164	if (TEST_RETURN < 0) {
165		if (tc->err != TEST_ERRNO)
166			tst_res(TFAIL | TTERRNO,
167				"mq_timedsend failed unexpectedly, expected %s",
168				tst_strerrno(tc->err));
169		else
170			tst_res(TPASS | TTERRNO, "mq_timedreceive failed expectedly");
171
172		if (*tc->fd == fd)
173			cleanup_queue(fd);
174
175		return;
176	}
177
178	TEST(mq_timedreceive(*tc->fd, rmsg, len, &prio, tc->rq));
179
180	if (*tc->fd == fd)
181		cleanup_queue(fd);
182
183	if (TEST_RETURN < 0) {
184		if (tc->err != TEST_ERRNO) {
185			tst_res(TFAIL | TTERRNO,
186				"mq_timedreceive failed unexpectedly, expected %s",
187				tst_strerrno(tc->err));
188			return;
189		}
190
191		if (tc->ret >= 0) {
192			tst_res(TFAIL | TTERRNO, "mq_timedreceive returned %ld, expected %d",
193					TEST_RETURN, tc->ret);
194			return;
195		}
196	}
197
198	if (tc->len != TEST_RETURN) {
199		tst_res(TFAIL, "mq_timedreceive wrong length %ld, expected %d",
200			TEST_RETURN, tc->len);
201		return;
202	}
203
204	if (tc->prio != prio) {
205		tst_res(TFAIL, "mq_timedreceive wrong prio %d, expected %d",
206			prio, tc->prio);
207		return;
208	}
209
210	for (j = 0; j < tc->len; j++) {
211		if (rmsg[j] != smsg[j]) {
212			tst_res(TFAIL,
213				"mq_timedreceive wrong data %d in %u, expected %d",
214				rmsg[j], i, smsg[j]);
215			return;
216		}
217	}
218
219	tst_res(TPASS, "mq_timedreceive returned %ld, priority %u, length: %zu",
220			TEST_RETURN, prio, len);
221}
222
223static struct tst_test test = {
224	.tcnt = ARRAY_SIZE(tcase),
225	.test = do_test,
226	.setup = setup_common,
227	.cleanup = cleanup_common,
228	.forks_child = 1,
229};
230