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