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
25static status_t
26remove_msg_queue(int msgID)
27{
28	return msgctl(msgID, IPC_RMID, 0);
29}
30
31struct message {
32	long type;
33	char text[20];
34};
35
36
37static void
38test_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
90static void
91test_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
135static void
136test_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
181static void
182test_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
232int
233main()
234{
235	test_msgget();
236	test_msgctl();
237	test_msgsnd();
238	test_msgrcv();
239
240	printf("\nAll tests OK\n");
241}
242