1 /* thread-util.c
2  * Implementation of thread utilities
3  *
4  * Yersinia
5  * By David Barroso <tomac@yersinia.net> and Alfredo Andres <aandreswork@hotmail.com>
6  * Copyright 2005-2017 Alfredo Andres and David Barroso
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version 2
11  * of the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
21  */
22 
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26 
27 #ifndef _REENTRANT
28 #define _REENTRANT
29 #endif
30 
31 #include <stdio.h>
32 #include <errno.h>
33 
34 #ifdef HAVE_SYS_TYPES_H
35 #include <sys/types.h>
36 #endif
37 
38 #ifdef HAVE_INTTYPES_H
39 #include <inttypes.h>
40 #endif
41 
42 #include <sys/socket.h>
43 
44 #ifdef HAVE_NETINET_IN_SYSTM_H
45 #include <netinet/in_systm.h>
46 #else
47 #ifdef HAVE_NETINET_IN_SYSTEM_H
48 #include <netinet/in_system.h>
49 #endif
50 #endif
51 
52 #include <netinet/in.h>
53 #include <arpa/inet.h>
54 #include <signal.h>
55 #include <time.h>
56 
57 #ifdef TIME_WITH_SYS_TIME
58 #include <sys/time.h>
59 #endif
60 
61 #ifdef HAVE_UNISTD_H
62 #include <unistd.h>
63 #endif
64 
65 #ifdef HAVE_STRING_H
66 #include <string.h>
67 #endif
68 
69 #ifdef HAVE_STRINGS_H
70 #include <strings.h>
71 #endif
72 
73 #ifdef HAVE_BSTRING_H
74 #include <bstring.h>
75 #endif
76 
77 #ifdef STDC_HEADERS
78 #include <stdlib.h>
79 #endif
80 
81 #include <stdarg.h>
82 
83 #include "thread-util.h"
84 
85 extern void write_log( u_int16_t mode, char *msg, ...);
86 
87 /*
88  * Create a thread
89  *
90 int8_t
91 thread_create(pthread_t *thread_id, void *thread_body , void *arg)
92 {
93    if (pthread_create(thread_id, NULL, thread_body, arg) != 0)
94    {
95       thread_error("pthread_create",errno);
96       return -1;
97    }
98 
99    return 0;
100 }
101 */
102 
thread_create(THREAD * thread,void * thread_body,void * arg)103 int8_t thread_create( THREAD *thread, void *thread_body, void *arg )
104 {
105     if ( ! pthread_mutex_init( &thread->finished, NULL ) )
106     {
107         if ( ! pthread_create( &thread->id, NULL, thread_body, arg ) )
108             return 0;
109 
110         thread_error( "thread_create pthread_create", errno );
111 
112         pthread_mutex_destroy( &thread->finished );
113     }
114     else
115         thread_error( "thread_create pthread_mutex_init", errno );
116 
117     return -1 ;
118 }
119 
120 
121 /*
122  * Destroy a thread with polling...
123  */
thread_destroy(THREAD * thread)124 int8_t thread_destroy( THREAD *thread )
125 {
126     int8_t ret = 0 ;
127 
128     write_log(0,"\n thread_destroy %X destroying %X...\n",(int)pthread_self(), (int)thread->id);
129 
130     thread->stop = 1;
131 
132     if ( ! PTHREAD_JOIN( thread ) )
133     {
134         if ( pthread_mutex_unlock( &thread->finished ) )
135         {
136             thread_error( "thread_destroy pthread_mutex_unlock", errno );
137             ret = -1 ;
138         }
139     }
140     else
141     {
142         thread_error(" thread_destroy PTHREAD_JOIN",errno);
143         ret = -1;
144     }
145 
146     write_log(0," thread_destroy %X after PTHREAD_JOIN %X...\n", (int)pthread_self(), (int)thread->id );
147 
148     thread->stop = 0;
149     thread->id   = 0;
150 
151     return ret;
152 }
153 
154 
155 /*
156  * Destroy a thread with cancellation...
157  */
158 int8_t
thread_destroy_cancel(pthread_t thread_id)159 thread_destroy_cancel(pthread_t thread_id)
160 {
161    pthread_t id = thread_id;
162 
163    if (pthread_cancel(id) != 0) {
164       thread_error(" thread_destroy_cancel pthread_cancel",errno);
165       return -1;
166    }
167 
168    if (pthread_join(id, NULL) != 0) {
169       thread_error(" thread_destroy_cancel pthread_join",errno);
170       return -1;
171    }
172 
173    return 0;
174 }
175 
176 
177 int8_t
thread_create_condsem(struct condsem * condsem)178 thread_create_condsem(struct condsem *condsem)
179 {
180    if (pthread_mutex_init(&condsem->mutex, NULL) != 0)
181    {
182       thread_error("pthread_mutex_init",errno);
183       return -1;
184    }
185 
186    if (pthread_cond_init(&condsem->condvar, NULL) != 0)
187    {
188       thread_error("pthread_cond_init",errno);
189       return -1;
190    }
191 
192    condsem->value = 0;
193 
194    return 0;
195 }
196 
197 
198 void
thread_delete_condsem(struct condsem * condsem)199 thread_delete_condsem(struct condsem *condsem)
200 {
201    if (pthread_mutex_destroy(&condsem->mutex) != 0)
202       thread_error("pthread_mutex_destroy(&condsem->mutex)",errno);
203 
204    if (pthread_cond_destroy(&condsem->condvar) != 0)
205       thread_error("pthread_cond_destroy(&condsem->condvar)",errno);
206 }
207 
208 
209 int8_t
thread_wait_cond(struct condsem * condsem)210 thread_wait_cond(struct condsem *condsem)
211 {
212    if (pthread_mutex_lock(&condsem->mutex) != 0)
213    {
214       thread_error("pthread_mutex_lock",errno);
215       return -1;
216    }
217 
218    while (condsem->value <= 0)
219    {
220       if (pthread_cond_wait(&condsem->condvar, &condsem->mutex) != 0)
221       {
222          thread_error("pthread_cond_wait",errno);
223          return -1;
224       }
225    }
226 
227    condsem->value--;
228 
229    if (pthread_mutex_unlock(&condsem->mutex) != 0)
230    {
231       thread_error("pthread_mutex_unlock",errno);
232       return -1;
233    }
234 
235    return 0;
236 }
237 
238 
239 
240 /*
241  * Wait for condition wariable with timeout.
242  * Be aware of disabling cancellation before calling this function!!!
243  * Return THREAD_TIMEOUT on timeout, -1 on error, 0 if Ok.
244  */
245 int8_t
thread_wait_cond_timed(struct condsem * condsem,struct timeval * timeout)246 thread_wait_cond_timed(struct condsem *condsem, struct timeval *timeout)
247 {
248    int ret=0;
249    struct timeval now;
250    struct timespec abstimeout;
251 
252    if (pthread_mutex_lock(&condsem->mutex) != 0)
253    {
254       thread_error("pthread_mutex_lock",errno);
255       return -1;
256    }
257 
258    gettimeofday(&now, NULL);
259 
260    abstimeout.tv_sec  = now.tv_sec + timeout->tv_sec;
261    abstimeout.tv_nsec = (now.tv_usec + timeout->tv_usec) * 1000;
262 
263    if (abstimeout.tv_nsec > 999999999)
264    {
265       abstimeout.tv_sec  += (abstimeout.tv_nsec/1000000000);
266       abstimeout.tv_nsec = (abstimeout.tv_nsec%1000000000);
267    }
268 
269    while (condsem->value <= 0)
270    {
271       ret = pthread_cond_timedwait(&condsem->condvar, &condsem->mutex,
272                                     &abstimeout);
273       if ( (ret == ETIMEDOUT) || (ret != 0) )
274          break;
275    }
276 
277    if (ret == ETIMEDOUT)
278    {
279       pthread_mutex_unlock(&condsem->mutex);
280       return THREAD_TIMEOUT;
281    }
282    else
283    {
284       if (ret)
285       {
286          thread_error(" pthread_cond_timedwait()",ret);
287          pthread_mutex_unlock(&condsem->mutex);
288          return -1;
289       }
290 
291       condsem->value--;
292    }
293 
294    pthread_mutex_unlock(&condsem->mutex);
295 
296    return 0;
297 }
298 
299 
300 
301 
302 int8_t
thread_signal_cond(struct condsem * condsem)303 thread_signal_cond(struct condsem *condsem)
304 {
305    if (pthread_mutex_lock(&condsem->mutex) != 0)
306    {
307       thread_error("pthread_mutex_lock",errno);
308       return -1;
309    }
310 
311    condsem->value++;
312 
313    if (pthread_mutex_unlock(&condsem->mutex) != 0)
314    {
315       thread_error("pthread_mutex_unlock",errno);
316       return -1;
317    }
318 
319    if (pthread_cond_signal(&condsem->condvar) != 0)
320    {
321       thread_error("pthread_cond_signal",errno);
322       return -1;
323    }
324 
325    return 0;
326 }
327 
328 
329 int8_t
thread_send_broadcast(struct condsem * condsem,int8_t total)330 thread_send_broadcast(struct condsem *condsem, int8_t total)
331 {
332    if (pthread_mutex_lock(&condsem->mutex) != 0)
333    {
334       thread_error("pthread_mutex_lock",errno);
335       return -1;
336    }
337 
338    condsem->value += total;
339 
340    if (pthread_mutex_unlock(&condsem->mutex) != 0)
341    {
342       thread_error("pthread_mutex_unlock",errno);
343       return -1;
344    }
345 
346    if (pthread_cond_broadcast(&condsem->condvar) != 0)
347    {
348       thread_error("pthread_send_broadcast",errno);
349       return -1;
350    }
351 
352    return 0;
353 }
354 
355 
356 void
thread_error(char * msg,int8_t errn)357 thread_error( char *msg, int8_t errn)
358 {
359 #ifdef HAVE_GLIBC_STRERROR_R
360   /* At least on glibc >= 2.0 Can anybody confirm?... */
361   char buf[64];
362 
363   write_log(0, "%s: (%d) %s -> %s\n", PACKAGE, (int)pthread_self(), msg,
364              strerror_r(errn, buf, sizeof(buf)));
365 #else
366 
367 #ifdef HAVE_STRERROR
368    write_log(0, "%s: (%d) %s -> %s\n", PACKAGE, (int)pthread_self(), msg,
369               strerror(errn) );
370 #else
371    write_log(0, "%s: (%d) %s -> %s\n", PACKAGE, (int)pthread_self(), msg,
372               sys_errlist[errn] );
373 #endif
374 
375 #endif
376 
377 }
378 
379 
380 void
thread_libnet_error(char * msg,libnet_t * lhandler)381 thread_libnet_error( char *msg, libnet_t *lhandler)
382 {
383    write_log(0, "%s: (%d) %s -> %s\n", PACKAGE,  (int)pthread_self(), msg,
384              libnet_geterror(lhandler));
385 }
386 
387 
388 /*
389  * Our own calloc function.
390  */
391 void *
thread_calloc_r(size_t size)392 thread_calloc_r(size_t size)
393 {
394    void *aux;
395 
396 #ifdef HAVE_CALLOC_R
397    aux = calloc_r(1,size);
398 #else
399    aux = calloc(1,size);
400 #endif
401 
402    return aux;
403 }
404 
405 
406 void
thread_free_r(void * ptr)407 thread_free_r(void *ptr)
408 {
409 #ifdef HAVE_FREE_R
410    free_r(ptr);
411 #else
412    free(ptr);
413 #endif
414 }
415 
416 
417 int
thread_usleep(unsigned long useconds)418 thread_usleep(unsigned long useconds)
419 {
420    int ret;
421 #ifdef HAVE_NANOSLEEP
422    struct timespec timeout;
423 #else
424    struct timeval timeout;
425 #endif
426 
427    if (useconds > 999999)
428       useconds = 999999;
429 
430    timeout.tv_sec  = 0;
431 
432 #ifdef HAVE_NANOSLEEP
433    timeout.tv_nsec = (useconds*1000);
434 #else
435    timeout.tv_usec = useconds;
436 #endif
437 
438 #ifdef HAVE_NANOSLEEP
439    ret = nanosleep(&timeout, NULL);
440 #else
441    ret = select(0,NULL,NULL,NULL,&timeout);
442 #endif
443 
444    return ret;
445 }
446 
447 /* vim:set tabstop=4:set expandtab:set shiftwidth=4:set textwidth=120: */
448