1 /*
2 * Copyright (c) 2010-2011 Balabit
3 * Copyright (c) 2010-2011 Balázs Scheidler
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 as published
7 * by the Free Software Foundation, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17 *
18 * As an additional exemption you are allowed to compile & link against the
19 * OpenSSL libraries as published by the OpenSSL project. See the file
20 * COPYING for details.
21 *
22 */
23
24 #include "syslog-ng.h"
25
26 #include <sys/types.h>
27 #include <sys/socket.h>
28 #include <sys/un.h>
29 #include <fcntl.h>
30 #include <signal.h>
31 #include <pthread.h>
32 #include <stdio.h>
33 #include <errno.h>
34 #include <unistd.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <criterion/criterion.h>
38
39 gboolean thread_exit = FALSE;
40 gboolean thread_started;
41 GCond thread_startup;
42 GMutex thread_lock;
43 pthread_t thread_handle;
44
45 void
sigusr1_handler(int signo)46 sigusr1_handler(int signo)
47 {
48 }
49
50 static void
setup_sigusr1(void)51 setup_sigusr1(void)
52 {
53 struct sigaction sa;
54
55 memset(&sa, 0, sizeof(sa));
56 /* NOTE: this has to be a real signal handler as SIG_IGN will not interrupt the accept call below */
57 sa.sa_handler = sigusr1_handler;
58 sa.sa_flags = 0;
59 sigaction(SIGUSR1, &sa, NULL);
60 }
61
62 static void
signal_startup(void)63 signal_startup(void)
64 {
65 thread_handle = pthread_self();
66 g_mutex_lock(&thread_lock);
67 thread_started = TRUE;
68 g_cond_signal(&thread_startup);
69 g_mutex_unlock(&thread_lock);
70 }
71
72 static gboolean
create_test_thread(GThreadFunc thread_func,gpointer data)73 create_test_thread(GThreadFunc thread_func, gpointer data)
74 {
75 GThread *t;
76 struct timespec nsleep;
77
78 thread_exit = FALSE;
79 thread_started = FALSE;
80 t = g_thread_new(NULL, thread_func, data);
81 g_mutex_lock(&thread_lock);
82 while (!thread_started)
83 g_cond_wait(&thread_startup, &thread_lock);
84 g_mutex_unlock(&thread_lock);
85 nsleep.tv_sec = 0;
86 nsleep.tv_nsec = 1e6;
87 nanosleep(&nsleep, NULL);
88 thread_exit = TRUE;
89 pthread_kill(thread_handle, SIGUSR1);
90 return (g_thread_join(t) != NULL);
91 }
92
93 int sock;
94
95 gpointer
accept_thread_func(gpointer args)96 accept_thread_func(gpointer args)
97 {
98 struct sockaddr_un peer;
99 gint new_sock;
100 gpointer result = NULL;
101
102 setup_sigusr1();
103 signal_startup();
104 while (1)
105 {
106 gint err;
107 socklen_t peer_size = sizeof(peer);
108
109 new_sock = accept(sock, (struct sockaddr *) &peer, &peer_size);
110 err = errno;
111
112 if (new_sock >= 0)
113 close(new_sock);
114 if (thread_exit)
115 {
116 fprintf(stderr, "accept woken up, errno=%s\n", g_strerror(err));
117 result = (gpointer) 0x1;
118 break;
119 }
120 }
121 close(sock);
122 return result;
123 }
124
125 int
test_accept_wakeup(void)126 test_accept_wakeup(void)
127 {
128 struct sockaddr_un s;
129
130 unlink("almafa");
131 sock = socket(PF_UNIX, SOCK_STREAM, 0);
132 s.sun_family = AF_UNIX;
133 strcpy(s.sun_path, "almafa");
134 cr_assert_not(bind(sock, (struct sockaddr *) &s, sizeof(s)), "error binding socket: %s", strerror(errno));
135 cr_assert_not(listen(sock, 255), "error in listen(): %s", strerror(errno));
136
137 return create_test_thread(accept_thread_func, NULL);
138 }
139
140 gpointer
read_thread_func(gpointer args)141 read_thread_func(gpointer args)
142 {
143 gint *pair = (gint *) args;
144 gpointer result = NULL;
145
146 setup_sigusr1();
147 signal_startup();
148 while (1)
149 {
150 gint err;
151 gchar buf[1024];
152 gint count G_GNUC_UNUSED = read(pair[1], buf, sizeof(buf));
153 err = errno;
154
155 if (thread_exit)
156 {
157 fprintf(stderr, "read woken up, errno=%s\n", g_strerror(err));
158 result = (gpointer) 0x1;
159 break;
160 }
161 }
162 close(pair[0]);
163 close(pair[1]);
164 return result;
165 }
166
167 int
test_read_wakeup(void)168 test_read_wakeup(void)
169 {
170 gint pair[2];
171
172 socketpair(PF_UNIX, SOCK_STREAM, 0, pair);
173 return create_test_thread(read_thread_func, pair);
174 }
175
Test(test_thread_wakeup,testcase)176 Test(test_thread_wakeup, testcase)
177 {
178
179 g_mutex_init(&thread_lock);
180 g_cond_init(&thread_startup);
181
182 cr_assert(test_accept_wakeup());
183 cr_assert(test_read_wakeup());
184
185 g_mutex_clear(&thread_lock);
186 g_cond_clear(&thread_startup);
187 }
188