1#include <errno.h>
2#include <netinet/in.h>
3#include <signal.h>
4#include <stdarg.h>
5#include <stdio.h>
6#include <stdlib.h>
7#include <string.h>
8#include <sys/socket.h>
9
10#include <OS.h>
11
12
13enum run_mode {
14	RUN_IGNORE_SIGNAL,
15	RUN_HANDLE_SIGNAL,
16	RUN_HANDLE_SIGNAL_RESTART
17};
18
19
20class Test {
21public:
22	Test(const char* name)
23		: fName(name)
24	{
25	}
26
27	virtual ~Test()
28	{
29	}
30
31	bool Run(run_mode mode)
32	{
33		fRunMode = mode;
34		fSignalHandlerCalled = false;
35
36		status_t error = Prepare();
37		if (error != B_OK)
38			return Error("Failed to prepare test: %s", strerror(error));
39
40		thread_id thread = spawn_thread(_ThreadEntry, fName, B_NORMAL_PRIORITY,
41			this);
42		if (thread < 0)
43			return Error("Failed to spawn thread: %s\n", strerror(thread));
44
45		resume_thread(thread);
46
47		// ...
48		// * interrupt without restart
49		// * interrupt with restart
50
51		snooze(100000);
52		kill(thread, SIGINT);
53
54		PrepareFinish();
55
56		status_t result;
57		wait_for_thread(thread, &result);
58
59		if (result != (Interrupted() ? B_INTERRUPTED : B_OK)) {
60			return Error("Unexpected syscall return value: %s\n",
61				strerror(result));
62		}
63
64		if ((RunMode() == RUN_IGNORE_SIGNAL) == fSignalHandlerCalled) {
65			if (RunMode() == RUN_IGNORE_SIGNAL)
66				return Error("Handler was called but shouldn't have been!");
67			else
68				return Error("Handler was not called!");
69		}
70
71		return Finish(Interrupted());
72	}
73
74	void Run()
75	{
76		printf("%s\n", fName);
77
78		struct {
79			const char*	name;
80			run_mode	mode;
81		} tests[] = {
82			{ "ignore signal", RUN_IGNORE_SIGNAL },
83			{ "handle signal no restart", RUN_HANDLE_SIGNAL },
84			{ "handle signal restart", RUN_HANDLE_SIGNAL_RESTART },
85			{}
86		};
87
88		for (int i = 0; tests[i].name != NULL; i++) {
89			printf("  %-30s: ", tests[i].name);
90			fflush(stdout);
91			ClearError();
92			if (Run(tests[i].mode))
93				printf("ok\n");
94			else
95				printf("failed (%s)\n", fError);
96
97			Cleanup();
98		}
99	}
100
101	run_mode RunMode() const { return fRunMode; }
102	bool Interrupted() const { return RunMode() == RUN_HANDLE_SIGNAL; }
103	bigtime_t TimeWaited() const { return fTimeWaited; }
104
105protected:
106	virtual status_t Prepare()
107	{
108		return B_OK;
109	}
110
111	virtual status_t DoSyscall() = 0;
112
113	virtual void HandleSignal()
114	{
115	}
116
117	virtual void PrepareFinish()
118	{
119	}
120
121	virtual bool Finish(bool interrupted)
122	{
123		return true;
124	}
125
126	virtual void Cleanup()
127	{
128	}
129
130	bool Error(const char* format,...)
131	{
132		va_list args;
133		va_start(args, format);
134		vsnprintf(fError, sizeof(fError), format, args);
135		va_end(args);
136
137		return false;
138	}
139
140	bool Check(bool condition, const char* format,...)
141	{
142		if (condition)
143			return true;
144
145		va_list args;
146		va_start(args, format);
147		vsnprintf(fError, sizeof(fError), format, args);
148		va_end(args);
149
150		return false;
151	}
152
153	void ClearError()
154	{
155		fError[0] = '\0';
156	}
157
158private:
159	static status_t _ThreadEntry(void* data)
160	{
161		return ((Test*)data)->_TestThread();
162	}
163
164	static void _SignalHandler(int signal, char* userData)
165	{
166		Test* self = (Test*)userData;
167
168		self->fSignalHandlerCalled = true;
169		self->HandleSignal();
170	}
171
172	status_t _TestThread()
173	{
174		// install handler
175		struct sigaction action;
176		if (RunMode() == RUN_IGNORE_SIGNAL)
177			action.sa_handler = SIG_IGN;
178		else
179			action.sa_handler = (void (*)(int))_SignalHandler;
180
181		action.sa_flags = RunMode() == RUN_HANDLE_SIGNAL_RESTART
182			? SA_RESTART : 0;
183
184		sigemptyset(&action.sa_mask);
185		action.sa_userdata = this;
186
187		sigaction(SIGINT, &action, NULL);
188
189		bigtime_t startTime = system_time();
190		status_t status = DoSyscall();
191		fTimeWaited = system_time() - startTime;
192
193		return status;
194	}
195
196private:
197	const char*	fName;
198	run_mode	fRunMode;
199	bool		fSignalHandlerCalled;
200	bigtime_t	fTimeWaited;
201	char		fError[1024];
202};
203
204
205class SnoozeTest : public Test {
206public:
207	SnoozeTest()
208		: Test("snooze")
209	{
210	}
211
212	virtual status_t DoSyscall()
213	{
214		return snooze(1000000);
215	}
216
217	virtual bool Finish(bool interrupted)
218	{
219		if (interrupted)
220			return Check(TimeWaited() < 200000, "waited too long");
221
222		return Check(TimeWaited() > 900000 && TimeWaited() < 1100000,
223			"waited %lld us instead of 1000000 us", TimeWaited());
224	}
225};
226
227
228class ReadTest : public Test {
229public:
230	ReadTest()
231		: Test("read")
232	{
233	}
234
235	virtual status_t Prepare()
236	{
237		fBytesRead = -1;
238		fFDs[0] = -1;
239		fFDs[1] = -1;
240
241		if (pipe(fFDs) != 0)
242			return errno;
243
244		return B_OK;
245	}
246
247	virtual status_t DoSyscall()
248	{
249		char buffer[256];
250		fBytesRead = read(fFDs[0], buffer, sizeof(buffer));
251
252		return fBytesRead < 0 ? errno : B_OK;
253	}
254
255	virtual void PrepareFinish()
256	{
257		write(fFDs[1], "Ingo", 4);
258	}
259
260	virtual bool Finish(bool interrupted)
261	{
262		if (interrupted)
263			return Check(fBytesRead < 0, "unexpected read");
264
265		return Check(fBytesRead == 4, "should have read 4 bytes, read only %ld "
266			"bytes", fBytesRead);
267	}
268
269	virtual void Cleanup()
270	{
271		close(fFDs[0]);
272		close(fFDs[1]);
273	}
274
275private:
276	bigtime_t	fTimeWaited;
277	ssize_t		fBytesRead;
278	int			fFDs[2];
279};
280
281
282class WriteTest : public Test {
283public:
284	WriteTest()
285		: Test("write")
286	{
287	}
288
289	virtual status_t Prepare()
290	{
291		fBytesWritten = -1;
292		fFDs[0] = -1;
293		fFDs[1] = -1;
294
295		if (pipe(fFDs) != 0)
296			return errno;
297
298		// fill pipe
299		fcntl(fFDs[1], F_SETFL, O_NONBLOCK);
300		while (write(fFDs[1], "a", 1) == 1);
301
302		return B_OK;
303	}
304
305	virtual status_t DoSyscall()
306	{
307		// blocking wait
308		fcntl(fFDs[1], F_SETFL, 0);
309		fBytesWritten = write(fFDs[1], "Ingo", 4);
310
311		return fBytesWritten < 0 ? errno : B_OK;
312	}
313
314	virtual void PrepareFinish()
315	{
316		char buffer[256];
317		read(fFDs[0], buffer, sizeof(buffer));
318	}
319
320	virtual bool Finish(bool interrupted)
321	{
322		if (interrupted)
323			return Check(fBytesWritten < 0, "unexpected write");
324
325		return Check(fBytesWritten == 4, "should have written 4 bytes, wrote only %ld "
326			"bytes", fBytesWritten);
327	}
328
329	virtual void Cleanup()
330	{
331		close(fFDs[0]);
332		close(fFDs[1]);
333	}
334
335private:
336	ssize_t		fBytesWritten;
337	int			fFDs[2];
338};
339
340
341class AcquireSwitchSemTest : public Test {
342public:
343	AcquireSwitchSemTest(bool useSwitch)
344		: Test(useSwitch ? "switch_sem" : "acquire_sem"),
345		fSwitch(useSwitch)
346	{
347	}
348
349	virtual status_t Prepare()
350	{
351		fSemaphore = create_sem(0, "test sem");
352
353		return (fSemaphore >= 0 ? B_OK : fSemaphore);
354	}
355
356	virtual status_t DoSyscall()
357	{
358		if (fSwitch)
359			return switch_sem(-1, fSemaphore);
360
361		return acquire_sem(fSemaphore);
362	}
363
364	virtual void PrepareFinish()
365	{
366		release_sem(fSemaphore);
367	}
368
369/*
370	virtual bool Finish(bool interrupted)
371	{
372//		int32 semCount = -1;
373//		get_sem_count(fSemaphore, &semCount);
374
375		if (interrupted)
376			return true;
377
378		return Check(fBytesWritten == 4, "should have written 4 bytes, wrote only %ld "
379			"bytes", fBytesWritten);
380	}
381*/
382
383	virtual void Cleanup()
384	{
385		delete_sem(fSemaphore);
386	}
387
388protected:
389	sem_id		fSemaphore;
390	bool		fSwitch;
391};
392
393
394class AcquireSwitchSemEtcTest : public Test {
395public:
396	AcquireSwitchSemEtcTest(bool useSwitch)
397		: Test(useSwitch ? "switch_sem_etc" : "acquire_sem_etc"),
398		fSwitch(useSwitch)
399	{
400	}
401
402	virtual status_t Prepare()
403	{
404		fSemaphore = create_sem(0, "test sem");
405
406		return fSemaphore >= 0 ? B_OK : fSemaphore;
407	}
408
409	virtual status_t DoSyscall()
410	{
411		status_t status;
412		if (fSwitch) {
413			status = switch_sem_etc(-1, fSemaphore, 1, B_RELATIVE_TIMEOUT,
414				1000000);
415		} else {
416			status = acquire_sem_etc(fSemaphore, 1, B_RELATIVE_TIMEOUT,
417				1000000);
418		}
419
420		if (!Interrupted() && status == B_TIMED_OUT)
421			return B_OK;
422
423		return status;
424	}
425
426	virtual bool Finish(bool interrupted)
427	{
428		if (interrupted)
429			return Check(TimeWaited() < 200000, "waited too long");
430
431		return Check(TimeWaited() > 900000 && TimeWaited() < 1100000,
432			"waited %lld us instead of 1000000 us", TimeWaited());
433	}
434
435	virtual void Cleanup()
436	{
437		delete_sem(fSemaphore);
438	}
439
440protected:
441	sem_id		fSemaphore;
442	bool		fSwitch;
443};
444
445
446class AcceptTest : public Test {
447public:
448	AcceptTest()
449		: Test("accept")
450	{
451	}
452
453	virtual status_t Prepare()
454	{
455		fAcceptedSocket = -1;
456
457		fServerSocket = socket(AF_INET, SOCK_STREAM, 0);
458		if (fServerSocket < 0) {
459			fprintf(stderr, "Could not open server socket: %s\n",
460				strerror(errno));
461			return errno;
462		}
463
464		int reuse = 1;
465		if (setsockopt(fServerSocket, SOL_SOCKET, SO_REUSEADDR, &reuse,
466				sizeof(int)) == -1) {
467			fprintf(stderr, "Could not make server socket reusable: %s\n",
468				strerror(errno));
469			return errno;
470		}
471
472		memset(&fServerAddress, 0, sizeof(sockaddr_in));
473		fServerAddress.sin_family = AF_INET;
474		fServerAddress.sin_addr.s_addr = INADDR_LOOPBACK;
475
476		if (bind(fServerSocket, (struct sockaddr *)&fServerAddress,
477				sizeof(struct sockaddr)) == -1) {
478			fprintf(stderr, "Could not bind server socket: %s\n",
479				strerror(errno));
480			return errno;
481		}
482
483		socklen_t length = sizeof(sockaddr_in);
484		getsockname(fServerSocket, (sockaddr*)&fServerAddress,
485			&length);
486
487		if (listen(fServerSocket, 10) == -1) {
488			fprintf(stderr, "Could not listen on server socket: %s\n",
489				strerror(errno));
490			return errno;
491		}
492
493		return B_OK;
494	}
495
496	virtual status_t DoSyscall()
497	{
498		sockaddr_in clientAddress;
499		socklen_t length = sizeof(struct sockaddr_in);
500
501		fAcceptedSocket = accept(fServerSocket,
502			(struct sockaddr *)&clientAddress, &length);
503		if (fAcceptedSocket == -1)
504			return errno;
505
506		return B_OK;
507	}
508
509	virtual void PrepareFinish()
510	{
511		if (Interrupted())
512			return;
513
514		int clientSocket = socket(AF_INET, SOCK_STREAM, 0);
515		if (clientSocket == -1) {
516			fprintf(stderr, "Could not open client socket: %s\n",
517				strerror(errno));
518			return;
519		}
520
521		if (connect(clientSocket, (struct sockaddr *)&fServerAddress,
522				sizeof(struct sockaddr)) == -1) {
523			fprintf(stderr, "Could not connect to server socket: %s\n",
524				strerror(errno));
525		}
526
527		close(clientSocket);
528	}
529
530	virtual bool Finish(bool interrupted)
531	{
532		if (interrupted)
533			return Check(fAcceptedSocket < 0, "got socket");
534
535		return Check(fAcceptedSocket >= 0, "got no socket");
536	}
537
538	virtual void Cleanup()
539	{
540		close(fAcceptedSocket);
541		close(fServerSocket);
542	}
543
544protected:
545	int			fServerSocket;
546	sockaddr_in	fServerAddress;
547	int			fAcceptedSocket;
548};
549
550
551class ReceiveTest : public Test {
552public:
553	ReceiveTest()
554		: Test("recv")
555	{
556	}
557
558	virtual status_t Prepare()
559	{
560		fBytesRead = -1;
561		fAcceptedSocket = -1;
562		fClientSocket = -1;
563
564		fServerSocket = socket(AF_INET, SOCK_STREAM, 0);
565		if (fServerSocket < 0) {
566			fprintf(stderr, "Could not open server socket: %s\n",
567				strerror(errno));
568			return errno;
569		}
570
571		int reuse = 1;
572		if (setsockopt(fServerSocket, SOL_SOCKET, SO_REUSEADDR, &reuse,
573				sizeof(int)) == -1) {
574			fprintf(stderr, "Could not make server socket reusable: %s\n",
575				strerror(errno));
576			return errno;
577		}
578
579		memset(&fServerAddress, 0, sizeof(sockaddr_in));
580		fServerAddress.sin_family = AF_INET;
581		fServerAddress.sin_addr.s_addr = INADDR_LOOPBACK;
582
583		if (bind(fServerSocket, (struct sockaddr *)&fServerAddress,
584				sizeof(struct sockaddr)) == -1) {
585			fprintf(stderr, "Could not bind server socket: %s\n",
586				strerror(errno));
587			return errno;
588		}
589
590		socklen_t length = sizeof(sockaddr_in);
591		getsockname(fServerSocket, (sockaddr*)&fServerAddress,
592			&length);
593
594		if (listen(fServerSocket, 10) == -1) {
595			fprintf(stderr, "Could not listen on server socket: %s\n",
596				strerror(errno));
597			return errno;
598		}
599
600		fClientSocket = socket(AF_INET, SOCK_STREAM, 0);
601		if (fClientSocket == -1) {
602			fprintf(stderr, "Could not open client socket: %s\n",
603				strerror(errno));
604			return errno;
605		}
606
607		fcntl(fClientSocket, F_SETFL, O_NONBLOCK);
608
609		if (connect(fClientSocket, (struct sockaddr *)&fServerAddress,
610				sizeof(struct sockaddr)) == -1) {
611			if (errno != EINPROGRESS) {
612				fprintf(stderr, "Could not connect to server socket: %s\n",
613					strerror(errno));
614				return errno;
615			}
616		}
617
618		sockaddr_in clientAddress;
619		length = sizeof(struct sockaddr_in);
620
621		fAcceptedSocket = accept(fServerSocket,
622			(struct sockaddr *)&clientAddress, &length);
623		if (fAcceptedSocket == -1)
624			return errno;
625
626		fcntl(fClientSocket, F_SETFL, 0);
627
628		snooze(100000);
629
630		return B_OK;
631	}
632
633	virtual status_t DoSyscall()
634	{
635		char buffer[256];
636		fBytesRead = recv(fAcceptedSocket, buffer, sizeof(buffer), 0);
637
638		return fBytesRead < 0 ? errno : B_OK;
639	}
640
641	virtual void PrepareFinish()
642	{
643		write(fClientSocket, "Axel", 4);
644	}
645
646	virtual bool Finish(bool interrupted)
647	{
648		if (interrupted)
649			return Check(fBytesRead < 0, "unexpected read");
650
651		return Check(fBytesRead == 4, "should have read 4 bytes, read only %ld "
652			"bytes", fBytesRead);
653	}
654
655	virtual void Cleanup()
656	{
657		close(fAcceptedSocket);
658		close(fServerSocket);
659		close(fClientSocket);
660	}
661
662protected:
663	int			fServerSocket;
664	sockaddr_in	fServerAddress;
665	int			fAcceptedSocket;
666	int			fClientSocket;
667	ssize_t		fBytesRead;
668};
669
670
671int
672main()
673{
674	Test* tests[] = {
675		new SnoozeTest,
676		new ReadTest,
677		new WriteTest,
678		new AcquireSwitchSemTest(false),
679		new AcquireSwitchSemTest(true),
680		new AcquireSwitchSemEtcTest(false),
681		new AcquireSwitchSemEtcTest(true),
682		new AcceptTest,
683		new ReceiveTest,
684		NULL
685	};
686
687	for (int i = 0; tests[i] != NULL; i++)
688		tests[i]->Run();
689
690	return 0;
691}
692