xref: /haiku/src/tests/system/libroot/posix/xsi_msg_queue_test1.cpp (revision 68ea01249e1e2088933cb12f9c28d4e5c5d1c9ef)
1 /*
2  * Copyright 2008, Salvatore Benedetto, salvatore.benedetto@gmail.com.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 #include <errno.h>
7 #include <fcntl.h>
8 #include <stdint.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <unistd.h>
13 #include <sys/mman.h>
14 #include <sys/msg.h>
15 #include <sys/stat.h>
16 #include <sys/time.h>
17 #include <sys/wait.h>
18 
19 #include <OS.h>
20 
21 #include "TestUnitUtils.h"
22 
23 #define KEY			((key_t)12345)
24 
25 static status_t
26 remove_msg_queue(int msgID)
27 {
28 	return msgctl(msgID, IPC_RMID, 0);
29 }
30 
31 struct message {
32 	long type;
33 	char text[20];
34 };
35 
36 
37 static void
38 test_msgget()
39 {
40 	TEST_SET("msgget({IPC_PRIVATE, key})");
41 
42 	const char* currentTest = NULL;
43 
44 	// Open private set with IPC_PRIVATE
45 	TEST("msgget(IPC_PRIVATE) - private");
46 	int msgID = msgget(IPC_PRIVATE, S_IRUSR | S_IWUSR);
47 	assert_posix_bool_success(msgID != -1);
48 
49 	// Destroy private msg_queue
50 	TEST("msgctl(IPC_RMID) - private");
51 	status_t status = remove_msg_queue(msgID);
52 	assert_posix_bool_success(status != -1);
53 
54 	// Open non-private non-existing set with IPC_CREAT
55 	TEST("msgget(KEY, IPC_CREAT) non-existing");
56 	msgID = msgget(KEY, IPC_CREAT | IPC_EXCL | S_IRUSR | S_IWUSR
57 		| S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
58 	assert_posix_bool_success(status != -1);
59 
60 	// Re-open non-private existing without IPC_CREAT
61 	TEST("msgget(KEY) re-open existing without IPC_CREAT");
62 	int returnID = msgget(KEY, 0);
63 	assert_equals(msgID, returnID);
64 
65 	// Re-open non-private existing with IPC_CREAT
66 	TEST("msgget(IPC_CREATE) re-open existing with IPC_CREAT");
67 	returnID = msgget(KEY, IPC_CREAT | IPC_EXCL);
68 	assert_posix_bool_success(errno == EEXIST);
69 
70 	// Destroy non-private msg_queue
71 	TEST("msgctl(IPC_RMID)");
72 	status = remove_msg_queue(msgID);
73 	assert_posix_bool_success(status != -1);
74 
75 	// Open non-private non-existing without IPC_CREAT
76 	TEST("msgget(IPC_CREATE) non-existing without IPC_CREAT");
77 	msgID = msgget(KEY, IPC_EXCL | S_IRUSR | S_IWUSR
78 		| S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
79 	assert_posix_bool_success(errno == ENOENT);
80 
81 	// Destroy non-existing msg_queue
82 	TEST("msgctl()");
83 	status = remove_msg_queue(msgID);
84 	assert_posix_bool_success(errno == EINVAL);
85 
86 	TEST("done");
87 }
88 
89 
90 static void
91 test_msgctl()
92 {
93 	TEST_SET("msgctl({IPC_STAT, IPC_SET, IPC_RMID})");
94 
95 	const char* currentTest = NULL;
96 
97 	// Open non-private non-existing set with IPC_CREAT
98 	TEST("msgget(IPC_CREATE) non-existing");
99 	int msgID = msgget(KEY, IPC_CREAT | IPC_EXCL | S_IRUSR | S_IWUSR
100 		| S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
101 	assert_posix_bool_success(msgID != -1);
102 
103 	// IPC_SET
104 	TEST("msgctl(IPC_SET)");
105 	struct msqid_ds msg_queue;
106 	memset(&msg_queue, 0, sizeof(struct msqid_ds));
107 	msg_queue.msg_perm.uid = getuid() + 3;
108 	msg_queue.msg_perm.gid = getgid() + 3;
109 	msg_queue.msg_perm.mode = 0666;
110 	msg_queue.msg_qbytes = 512;
111 	status_t status = msgctl(msgID, IPC_SET, &msg_queue);
112 	assert_posix_bool_success(status != 1);
113 
114 	// IPC_STAT set
115 	TEST("msgctl(IPC_STAT)");
116 	memset(&msg_queue, 0, sizeof(struct msqid_ds));
117 	status = msgctl(msgID, IPC_STAT, &msg_queue);
118 	assert_posix_bool_success(status != 1);
119 	TEST("msgctl(IPC_STAT): number of bytes");
120 	assert_equals((msglen_t)msg_queue.msg_qbytes, (msglen_t)512);
121 	TEST("msgctl(IPC_STAT): uid");
122 	assert_equals(msg_queue.msg_perm.uid, getuid() + 3);
123 	TEST("msgctl(IPC_STAT): gid");
124 	assert_equals(msg_queue.msg_perm.gid, getgid() + 3);
125 
126 	// Destroy non-private msg_queue
127 	TEST("msgctl(IPC_RMID)");
128 	status = remove_msg_queue(msgID);
129 	assert_posix_bool_success(status != 1);
130 
131 	TEST("done");
132 }
133 
134 
135 static void
136 test_msgsnd()
137 {
138 	TEST_SET("msgsnd({EAGAIN, send})");
139 
140 	const char* currentTest = NULL;
141 
142 	// Open non-private non-existing set with IPC_CREAT
143 	TEST("msgget(IPC_CREATE) non-existing");
144 	int msgID = msgget(KEY, IPC_CREAT | IPC_EXCL | S_IRUSR | S_IWUSR
145 		| S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
146 	assert_posix_bool_success(msgID != -1);
147 
148 	// Send simple message
149 	TEST("msgsnd(simple message)");
150 	struct message msg;
151 	msg.type = 0;
152 	strcpy(msg.text, "Message to send\n");
153 	status_t status = msgsnd((key_t)msgID, (void *)&msg, 20, 0);
154 	assert_posix_bool_success(status != 1);
155 
156 	// IPC_SET
157 	TEST("msgctl(IPC_SET) - set limit to 512");
158 	struct msqid_ds msg_queue;
159 	memset(&msg_queue, 0, sizeof(struct msqid_ds));
160 	msg_queue.msg_perm.uid = getuid() + 3;
161 	msg_queue.msg_perm.gid = getgid() + 3;
162 	msg_queue.msg_perm.mode = 0666;
163 	msg_queue.msg_qbytes = 512;
164 	status = msgctl(msgID, IPC_SET, &msg_queue);
165 	assert_posix_bool_success(status != 1);
166 
167 	// Send big message IPC_NOWAIT
168 	TEST("msgsnd(IPC_NOWAIT)");
169 	msgsnd((key_t)msgID, (void *)&msg, 500, IPC_NOWAIT);
170 	assert_posix_bool_success(errno == EAGAIN);
171 
172 	// Destroy non-private msg_queue
173 	TEST("msgctl(IPC_RMID)");
174 	status = remove_msg_queue(msgID);
175 	assert_posix_bool_success(status != 1);
176 
177 	TEST("done");
178 }
179 
180 
181 static void
182 test_msgrcv()
183 {
184 	TEST_SET("msgrcv({IPC_STAT, IPC_SET, IPC_RMID})");
185 
186 	const char* currentTest = NULL;
187 
188 	// Open non-private non-existing set with IPC_CREAT
189 	TEST("msgget(IPC_CREATE) non-existing");
190 	int msgID = msgget(KEY, IPC_CREAT | IPC_EXCL | S_IRUSR | S_IWUSR
191 		| S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
192 	assert_posix_bool_success(msgID != -1);
193 
194 	// Receive simple message
195 	TEST("msgrcv(IPC_NOWAIT)");
196 	struct message msg;
197 	memset(&msg, 0, sizeof(struct message));
198 	msgrcv((key_t)msgID, (void *)&msg, 20, 0, IPC_NOWAIT);
199 	assert_posix_bool_success(errno == ENOMSG);
200 
201 	pid_t child = fork();
202 	if (child == 0) {
203 		// Send a simple message
204 		TEST("msgsnd(simple message)");
205 		struct message smsg;
206 		msg.type = 0;
207 		strcpy(msg.text, "Message to send\n");
208 		status_t status = msgsnd((key_t)msgID, (void *)&smsg, 20, 0);
209 		assert_posix_bool_success(status != 1);
210 		exit(0);
211 	}
212 
213 	wait_for_child(child);
214 	TEST("msgrcv(E2BIG)");
215 	msgrcv((key_t)msgID, (void *)&msg, 10, 0, IPC_NOWAIT);
216 	assert_posix_bool_success(errno == E2BIG);
217 
218 	TEST("msgrcv(MSG_NOERROR)");
219 	status_t status
220 		= msgrcv((key_t)msgID, (void *)&msg, 10, 0, IPC_NOWAIT | MSG_NOERROR);
221 	assert_posix_bool_success(status != -1);
222 
223 	// Destroy non-private msg_queue
224 	TEST("msgctl(IPC_RMID)");
225 	status = remove_msg_queue(msgID);
226 	assert_posix_bool_success(status != 1);
227 
228 	TEST("done");
229 }
230 
231 
232 int
233 main()
234 {
235 	test_msgget();
236 	test_msgctl();
237 	test_msgsnd();
238 	test_msgrcv();
239 
240 	printf("\nAll tests OK\n");
241 }
242