1 /*
2     ettercap -- thread handling
3 
4     Copyright (C) ALoR & NaGA
5 
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10 
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15 
16     You should have received a copy of the GNU General Public License
17     along with this program; if not, write to the Free Software
18     Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 
20 */
21 
22 #include <ec.h>
23 #include <ec_threads.h>
24 
25 #include <pthread.h>
26 #include <errno.h>
27 
28 struct thread_list {
29    struct ec_thread t;
30    LIST_ENTRY (thread_list) next;
31 };
32 
33 
34 /* global data */
35 
36 /* a value to be used to return errors in fuctcions using pthread_t values */
37 static pthread_t EC_PTHREAD_NULL = 0;
38 #define EC_PTHREAD_SELF EC_PTHREAD_NULL
39 
40 #define DETACHED_THREAD 1
41 #define JOINABLE_THREAD 0
42 
43 static LIST_HEAD(, thread_list) thread_list_head;
44 
45 static pthread_mutex_t threads_mutex = PTHREAD_MUTEX_INITIALIZER;
46 #define THREADS_LOCK     do{ pthread_mutex_lock(&threads_mutex); } while(0)
47 #define THREADS_UNLOCK   do{ pthread_mutex_unlock(&threads_mutex); } while(0)
48 
49 static pthread_mutex_t init_mtx = PTHREAD_MUTEX_INITIALIZER;
50 static pthread_cond_t init_cond = PTHREAD_COND_INITIALIZER;
51 #define INIT_LOCK     do{ DEBUG_MSG("thread_init_lock"); pthread_mutex_lock(&init_mtx); } while(0)
52 #define INIT_UNLOCK   do{ DEBUG_MSG("thread_init_unlock"); pthread_mutex_unlock(&init_mtx); } while(0)
53 
54 /* protos... */
55 
56 pthread_t ec_thread_detached(char *name, char *desc, void *(*function)(void *), void *args, int detached);
57 
58 /*******************************************/
59 
60 /* returns the name of a thread */
61 
ec_thread_getname(pthread_t id)62 char * ec_thread_getname(pthread_t id)
63 {
64    struct thread_list *current;
65    char *name;
66 
67    if (pthread_equal(id, EC_PTHREAD_SELF))
68       id = pthread_self();
69 
70    /* don't lock here to avoid deadlock in debug messages */
71 #ifndef DEBUG
72    THREADS_LOCK;
73 #endif
74 
75    LIST_FOREACH(current, &thread_list_head, next) {
76       if (pthread_equal(current->t.id, id)) {
77          name = current->t.name;
78 #ifndef DEBUG
79          THREADS_UNLOCK;
80 #endif
81          return name;
82       }
83    }
84 
85 #ifndef DEBUG
86    THREADS_UNLOCK;
87 #endif
88 
89    return "NR_THREAD";
90 }
91 
92 /*
93  * returns the pid of a thread
94  * ZERO if not found !! (take care, not -E_NOTFOUND !)
95  */
96 
ec_thread_getpid(char * name)97 pthread_t ec_thread_getpid(char *name)
98 {
99    struct thread_list *current;
100    pthread_t pid;
101 
102    /*
103     * if "name" is explicitely set up NULL, the top-level pthread_t
104     * is returned w/o iterating through the thread-list
105     */
106    if (name == NULL)
107       return EC_PTHREAD_NULL;
108 
109    THREADS_LOCK;
110 
111    LIST_FOREACH(current, &thread_list_head, next) {
112       if (!strcasecmp(current->t.name,name)) {
113          pid = current->t.id;
114          THREADS_UNLOCK;
115          return pid;
116       }
117    }
118 
119    THREADS_UNLOCK;
120 
121    return EC_PTHREAD_NULL;
122 }
123 
124 /* returns the description of a thread */
125 
ec_thread_getdesc(pthread_t id)126 char * ec_thread_getdesc(pthread_t id)
127 {
128    struct thread_list *current;
129    char *desc;
130 
131    if (pthread_equal(id, EC_PTHREAD_SELF))
132       id = pthread_self();
133 
134    THREADS_LOCK;
135 
136    LIST_FOREACH(current, &thread_list_head, next) {
137       if (pthread_equal(current->t.id, id)) {
138          desc = current->t.description;
139          THREADS_UNLOCK;
140          return desc;
141       }
142    }
143 
144    THREADS_UNLOCK;
145 
146    return "";
147 }
148 
149 
150 /* add a thread in the thread list */
ec_thread_register(pthread_t id,char * name,char * desc)151 void ec_thread_register(pthread_t id, char *name, char *desc)
152 {
153    ec_thread_register_detached(id, name, desc, JOINABLE_THREAD);
154 }
155 
ec_thread_register_detached(pthread_t id,char * name,char * desc,int detached)156 void ec_thread_register_detached(pthread_t id, char *name, char *desc, int detached)
157 {
158    struct thread_list *current, *newelem;
159 
160    if (pthread_equal(id, EC_PTHREAD_SELF))
161       id = pthread_self();
162 
163    DEBUG_MSG("ec_thread_register -- [%lu] %s", PTHREAD_ID(id), name);
164 
165    SAFE_CALLOC(newelem, 1, sizeof(struct thread_list));
166 
167    newelem->t.id = id;
168    newelem->t.name = strdup(name);
169    newelem->t.description = strdup(desc);
170    newelem->t.detached = detached;
171 
172    THREADS_LOCK;
173 
174    LIST_FOREACH(current, &thread_list_head, next) {
175       if (pthread_equal(current->t.id, id)) {
176          SAFE_FREE(current->t.name);
177          SAFE_FREE(current->t.description);
178          LIST_REPLACE(current, newelem, next);
179          SAFE_FREE(current);
180          THREADS_UNLOCK;
181          return;
182       }
183    }
184 
185    LIST_INSERT_HEAD(&thread_list_head, newelem, next);
186 
187    THREADS_UNLOCK;
188 
189 }
190 
191 /*
192  * creates a new thread on the given function
193  */
194 
ec_thread_new(char * name,char * desc,void * (* function)(void *),void * args)195 pthread_t ec_thread_new(char *name, char *desc, void *(*function)(void *), void *args) {
196    return ec_thread_new_detached(name, desc, function, args, JOINABLE_THREAD);
197 }
198 
ec_thread_new_detached(char * name,char * desc,void * (* function)(void *),void * args,int detached)199 pthread_t ec_thread_new_detached(char *name, char *desc, void *(*function)(void *), void *args, int detached)
200 {
201    pthread_t id;
202    int e;
203 
204    DEBUG_MSG("ec_thread_new -- %s detached %d", name, detached);
205 
206    /*
207     * lock the mutex to syncronize with the new thread.
208     * the newly created thread will call ec_thread_init(),
209     * so at the end of this function we are sure that the
210     * thread had be initialized
211     */
212    INIT_LOCK;
213 
214    if (detached == DETACHED_THREAD) {
215       pthread_attr_t attr;
216       pthread_attr_init(&attr);
217       pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
218       if ((e = pthread_create(&id, &attr, function, args)) != 0)
219          ERROR_MSG("not enough resources to create a new thread in this process: %s", strerror(e));
220    }else {
221       if ((e = pthread_create(&id, NULL, function, args)) != 0)
222          ERROR_MSG("not enough resources to create a new thread in this process: %s", strerror(e));
223    }
224 
225    ec_thread_register_detached(id, name, desc, detached);
226 
227    DEBUG_MSG("ec_thread_new -- %lu created ", PTHREAD_ID(id));
228 
229    if ((e = pthread_cond_wait(&init_cond, &init_mtx)))
230       ERROR_MSG("waiting on init_cond: %s", strerror(e));
231    INIT_UNLOCK;
232 
233    return id;
234 }
235 
236 /*
237  * set the state of a thread
238  * all the new thread MUST call this on startup
239  */
ec_thread_init(void)240 void ec_thread_init(void)
241 {
242    pthread_t id = pthread_self();
243    int e;
244 
245    DEBUG_MSG("ec_thread_init -- %lu", PTHREAD_ID(id));
246 
247    INIT_LOCK;
248 
249    /*
250     * allow a thread to be cancelled as soon as the
251     * cancellation  request  is received
252     */
253    pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
254    pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
255 
256    /* sync with the creator */
257    if ((e = pthread_cond_signal(&init_cond)))
258       ERROR_MSG("raising init_cond: %s", strerror(e));
259    INIT_UNLOCK;
260 
261    DEBUG_MSG("ec_thread_init -- (%lu) ready and syncronized",  PTHREAD_ID(id));
262 }
263 
264 /*
265  * destroy a thread in the list
266  */
ec_thread_destroy(pthread_t id)267 void ec_thread_destroy(pthread_t id)
268 {
269    struct thread_list *current;
270 
271    if (pthread_equal(id, EC_PTHREAD_SELF))
272       id = pthread_self();
273 
274    DEBUG_MSG("ec_thread_destroy -- terminating %lu [%s]", PTHREAD_ID(id), ec_thread_getname(id));
275 
276 
277    /* send the cancel signal to the thread */
278    pthread_cancel((pthread_t)id);
279 
280 
281    DEBUG_MSG("ec_thread_destroy -- [%s] terminated", ec_thread_getname(id));
282 
283    THREADS_LOCK;
284 
285    LIST_FOREACH(current, &thread_list_head, next) {
286       if (pthread_equal(current->t.id, id)) {
287 #ifndef BROKEN_PTHREAD_JOIN
288          if (!current->t.detached) {
289             DEBUG_MSG("ec_thread_destroy: pthread_join");
290             /* wait until it has finished */
291             pthread_join((pthread_t)id, NULL);
292          }
293 #endif
294          SAFE_FREE(current->t.name);
295          SAFE_FREE(current->t.description);
296          LIST_REMOVE(current, next);
297          SAFE_FREE(current);
298          THREADS_UNLOCK;
299          return;
300       }
301    }
302 
303    THREADS_UNLOCK;
304 
305 }
306 
307 
308 /*
309  * kill all the registerd thread but
310  * the calling one
311  */
312 
ec_thread_kill_all(void)313 void ec_thread_kill_all(void)
314 {
315    struct thread_list *current, *old;
316    pthread_t id = pthread_self();
317 
318    DEBUG_MSG("ec_thread_kill_all -- caller %lu [%s]", PTHREAD_ID(id), ec_thread_getname(id));
319 
320    THREADS_LOCK;
321 
322 #ifdef OS_WINDOWS
323    /* prevent hanging UI. Not sure how this works, but it does... */
324    if (EC_GBL_IFACE->pcap)
325       ec_win_pcap_stop(EC_GBL_IFACE->pcap);
326 #endif
327 
328    LIST_FOREACH_SAFE(current, &thread_list_head, next, old) {
329       /* skip ourself */
330       if (!pthread_equal(current->t.id, id)) {
331          DEBUG_MSG("ec_thread_kill_all -- terminating %lu [%s]", PTHREAD_ID(current->t.id), current->t.name);
332 
333          /* send the cancel signal to the thread */
334          pthread_cancel((pthread_t)current->t.id);
335 
336 #ifndef BROKEN_PTHREAD_JOIN
337          if (!current->t.detached) {
338             DEBUG_MSG("ec_thread_destroy: pthread_join");
339             /* wait until it has finished */
340             pthread_join(current->t.id, NULL);
341          }
342 #endif
343 
344          DEBUG_MSG("ec_thread_kill_all -- [%s] terminated", current->t.name);
345 
346          SAFE_FREE(current->t.name);
347          SAFE_FREE(current->t.description);
348          LIST_REMOVE(current, next);
349          SAFE_FREE(current);
350       }
351    }
352 
353    THREADS_UNLOCK;
354 }
355 
356 /*
357  * used by a thread that wants to terminate itself
358  */
ec_thread_exit(void)359 void ec_thread_exit(void)
360 {
361    struct thread_list *current, *old;
362    pthread_t id = pthread_self();
363 
364    DEBUG_MSG("ec_thread_exit -- caller %lu [%s]", PTHREAD_ID(id), ec_thread_getname(id));
365 
366    THREADS_LOCK;
367 
368    LIST_FOREACH_SAFE(current, &thread_list_head, next, old) {
369       /* delete our entry */
370       if (pthread_equal(current->t.id, id)) {
371 
372       /* thread is attempting to shut down on its own, check and see if the thread is detached,
373          if not set is as a detached thread since when a thread calls this method, there is no thread
374          that will do the pthread_join to force it to release all of its resources */
375          if (!current->t.detached) {
376             pthread_detach(id);
377          }
378 
379          SAFE_FREE(current->t.name);
380          SAFE_FREE(current->t.description);
381          LIST_REMOVE(current, next);
382          SAFE_FREE(current);
383       }
384    }
385 
386    THREADS_UNLOCK;
387 
388    /* perform a clean exit of the thread */
389    pthread_exit(0);
390 
391 }
392 
393 /* EOF */
394 
395 // vim:ts=3:expandtab
396 
397