1 | /***************************************
2 | $Revision: 1.12 $
3 |
4 | Example code: A thread.
5 |
6 | Status: NOT REVUED, NOT TESTED
7 |
8 | Authors: Chris Ottrey
9 | Joao Damas
10 |
11 | +html+ <DL COMPACT>
12 | +html+ <DT>Online References:
13 | +html+ <DD><UL>
14 | +html+ </UL>
15 | +html+ </DL>
16 |
17 | ******************/ /******************
18 | Modification History:
19 | ottrey (02/03/1999) Created.
20 | ottrey (08/03/1999) Modified.
21 | ottrey (17/06/1999) Stripped down.
22 | joao (22/06/1999) Redid thread startup
23 | ******************/ /******************
24 | Copyright (c) 1999 RIPE NCC
25 |
26 | All Rights Reserved
27 |
28 | Permission to use, copy, modify, and distribute this software and its
29 | documentation for any purpose and without fee is hereby granted,
30 | provided that the above copyright notice appear in all copies and that
31 | both that copyright notice and this permission notice appear in
32 | supporting documentation, and that the name of the author not be
33 | used in advertising or publicity pertaining to distribution of the
34 | software without specific, written prior permission.
35 |
36 | THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
37 | ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL
38 | AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
39 | DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
40 | AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
41 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
42 | ***************************************/
43 | #include <pthread.h> /* Posix thread library */
44 | #include <stdio.h>
45 | #include <strings.h>
46 |
47 | #include "thread.h"
48 | #include "socket.h"
49 | #include "protocol_whois.h"
50 | #include "protocol_config.h"
51 | #include "constants.h"
52 | #include "memwrap.h"
53 |
54 | /*+ String sizes +*/
55 | #define STR_S 63
56 | #define STR_M 255
57 | #define STR_L 1023
58 | #define STR_XL 4095
59 | #define STR_XXL 16383
60 |
61 | /*+ Mutex lock. Used for synchronizing changes. +*/
62 | pthread_mutex_t Whois_thread_count_lock;
63 | pthread_mutex_t Config_thread_count_lock;
64 | pthread_mutex_t Mirror_thread_count_lock;
65 |
66 | /*+ The number of threads. +*/
67 | int Whois_thread_count;
68 | int Config_thread_count;
69 | int Mirror_thread_count;
70 |
71 | typedef struct th_args {
72 | void * function;
73 | int sock;
74 | } th_args;
75 |
76 | static void log_print(const char *arg) {
77 | FILE *logf;
78 |
79 | if (CO_get_thread_logging() == 1) {
80 | if (strcmp(CO_get_thread_logfile(), "stdout") == 0) {
81 | printf(arg);
82 | }
83 | else {
84 | logf = fopen(CO_get_thread_logfile(), "a");
85 | fprintf(logf, arg);
86 | fclose(logf);
87 | }
88 | }
89 |
90 | } /* log_print() */
91 |
92 | /* TH_acquire_read_lock() */
93 | /*++++++++++++++++++++++++++++++++++++++
94 |
95 | Aquire a readers lock.
96 |
97 | rw_lock_t *prw_lock Readers writers lock.
98 |
99 | Reference: "Multithreaded Programming Techniques - Prasad p.192"
100 | More:
101 | +html+ <PRE>
102 | Author:
103 | ottrey
104 | +html+ </PRE>
105 | ++++++++++++++++++++++++++++++++++++++*/
106 | void TH_acquire_read_lock(rw_lock_t *prw_lock) {
107 | pthread_mutex_lock(&prw_lock->rw_mutex);
108 |
109 | while (prw_lock->rw_count < 0) {
110 | pthread_cond_wait(&prw_lock->rw_cond, &prw_lock->rw_mutex);
111 | }
112 |
113 | ++prw_lock->rw_count;
114 | pthread_mutex_unlock(&prw_lock->rw_mutex);
115 |
116 | } /* TH_acquire_read_lock() */
117 |
118 | /* TH_release_read_lock() */
119 | /*++++++++++++++++++++++++++++++++++++++
120 |
121 | Release a readers lock.
122 |
123 | rw_lock_t *prw_lock Readers writers lock.
124 |
125 | Reference: "Multithreaded Programming Techniques - Prasad p.192"
126 | More:
127 | +html+ <PRE>
128 | Author:
129 | ottrey
130 | +html+ </PRE>
131 | ++++++++++++++++++++++++++++++++++++++*/
132 | void TH_release_read_lock(rw_lock_t *prw_lock) {
133 | pthread_mutex_lock(&prw_lock->rw_mutex);
134 |
135 | --prw_lock->rw_count;
136 |
137 | if (!prw_lock->rw_count) {
138 | pthread_cond_signal(&prw_lock->rw_cond);
139 | }
140 |
141 | pthread_mutex_unlock(&prw_lock->rw_mutex);
142 |
143 | } /* TH_release_read_lock() */
144 |
145 | /* TH_acquire_write_lock() */
146 | /*++++++++++++++++++++++++++++++++++++++
147 |
148 | Aquire a writers lock.
149 |
150 | rw_lock_t *prw_lock Readers writers lock.
151 |
152 | Reference: "Multithreaded Programming Techniques - Prasad p.192"
153 | More:
154 | +html+ <PRE>
155 | Author:
156 | ottrey
157 | +html+ </PRE>
158 | ++++++++++++++++++++++++++++++++++++++*/
159 | void TH_acquire_write_lock(rw_lock_t *prw_lock) {
160 | pthread_mutex_lock(&prw_lock->rw_mutex);
161 |
162 | while (prw_lock->rw_count != 0) {
163 | pthread_cond_wait(&prw_lock->rw_cond, &prw_lock->rw_mutex);
164 | }
165 |
166 | prw_lock->rw_count = -1;
167 | pthread_mutex_unlock(&prw_lock->rw_mutex);
168 |
169 | } /* TH_acquire_write_lock() */
170 |
171 | /* TH_release_write_lock() */
172 | /*++++++++++++++++++++++++++++++++++++++
173 |
174 | Release a writers lock.
175 |
176 | rw_lock_t *prw_lock Readers writers lock.
177 |
178 | Reference: "Multithreaded Programming Techniques - Prasad p.192"
179 | More:
180 | +html+ <PRE>
181 | Author:
182 | ottrey
183 | +html+ </PRE>
184 | ++++++++++++++++++++++++++++++++++++++*/
185 | void TH_release_write_lock(rw_lock_t *prw_lock) {
186 | pthread_mutex_lock(&prw_lock->rw_mutex);
187 | prw_lock->rw_count = 0;
188 | pthread_mutex_unlock(&prw_lock->rw_mutex);
189 | pthread_cond_broadcast(&prw_lock->rw_cond);
190 |
191 | } /* TH_release_write_lock() */
192 |
193 | /* TH_init_read_write_lock() */
194 | /*++++++++++++++++++++++++++++++++++++++
195 |
196 | Initialize a readers/writers lock.
197 |
198 | rw_lock_t *prw_lock Readers writers lock.
199 |
200 | Side effect: the lock is set to open(?)
201 |
202 | Reference: "Multithreaded Programming Techniques - Prasad p.192"
203 | More:
204 | +html+ <PRE>
205 | Author:
206 | ottrey
207 | +html+ </PRE>
208 | ++++++++++++++++++++++++++++++++++++++*/
209 | void TH_init_read_write_lock(rw_lock_t *prw_lock) {
210 | pthread_mutex_init(&prw_lock->rw_mutex, NULL);
211 | pthread_cond_init(&prw_lock->rw_cond, NULL);
212 | prw_lock->rw_count = 0;
213 |
214 | } /* TH_init_read_write_lock() */
215 |
216 | int TH_get_id(void) {
217 |
218 | return (int)pthread_self();
219 |
220 | } /* TH_get_id() */
221 |
222 | /* TH_to_string() */
223 | char *TH_to_string(void) {
224 | char *thread_info;
225 | char tmp[STR_L];
226 | char thread_info_buffer[STR_XL];
227 |
228 | strcpy(thread_info_buffer, "Thread = { ");
229 |
230 | sprintf(tmp, "[pthread_self] = \"%d\" ", pthread_self());
231 | strcat(thread_info_buffer, tmp);
232 |
233 | /*
234 | thread_name = (char *)pthread_getspecific(Name);
235 |
236 | if (thread_name == NULL ) {
237 | sprintf(tmp, "[Name] = \"%s\" ", "didn't work!");
238 | }
239 | else {
240 | sprintf(tmp, "[Name] = \"%s\" ", thread_name);
241 | }
242 | strcat(thread_info_buffer, tmp);
243 | */
244 |
245 | strcat(thread_info_buffer, "}");
246 |
247 | //thread_info = (char *)calloc(1, strlen(thread_info_buffer)+1);
248 | dieif( wr_malloc((void **)&thread_info,
249 | strlen(thread_info_buffer)+1) != UT_OK);
250 |
251 | strcpy(thread_info, thread_info_buffer);
252 |
253 | return thread_info;
254 | } /* TH_to_string() */
255 |
256 | /* TH_do_whois() */
257 | /*++++++++++++++++++++++++++++++++++++++
258 |
259 | Handle whois connections.
260 |
261 | void *arg The socket to connect to. (It has to be passed in this way for this thread routine.)
262 |
263 | More:
264 | +html+ <PRE>
265 | Author:
266 | joao
267 | +html+ </PRE>
268 | ++++++++++++++++++++++++++++++++++++++*/
269 | void TH_do_whois(void *arg) {
270 | int sock = (int)arg;
271 | char print_buf[STR_M];
272 |
273 | sprintf(print_buf, "Whois: Child thread [%d]: Socket number = %d\n", pthread_self(), sock); log_print(print_buf); strcpy(print_buf, "");
274 |
275 | /* Use a mutex to update the global whois thread counter. */
276 | pthread_mutex_lock(&Whois_thread_count_lock);
277 | Whois_thread_count++;
278 | sprintf(print_buf, "Whois_thread_count++=%d\n", Whois_thread_count); log_print(print_buf); strcpy(print_buf, "");
279 | pthread_mutex_unlock(&Whois_thread_count_lock);
280 |
281 | PW_interact(sock);
282 |
283 | /* Use a mutex to update the global whois thread counter. */
284 | pthread_mutex_lock(&Whois_thread_count_lock);
285 | Whois_thread_count--;
286 | sprintf(print_buf, "Whois_thread_count--=%d\n", Whois_thread_count); log_print(print_buf); strcpy(print_buf, "");
287 | pthread_mutex_unlock(&Whois_thread_count_lock);
288 |
289 | pthread_exit((void *)0);
290 |
291 | } /* TH_do_whois() */
292 |
293 | /* TH_do_config() */
294 | /*++++++++++++++++++++++++++++++++++++++
295 |
296 | Handle config connections.
297 |
298 | void *arg The socket to connect to. (It has to be passed in this way for this
299 | thread routine.)
300 |
301 | More:
302 | +html+ <PRE>
303 | Author:
304 | joao
305 | +html+ </PRE>
306 | ++++++++++++++++++++++++++++++++++++++*/
307 | void TH_do_config(void *arg) {
308 | int sock = (int)arg;
309 | char print_buf[STR_M];
310 |
311 | sprintf(print_buf, "Config: Child thread [%d]: Socket number = %d\n", pthread_self(), sock); log_print(print_buf); strcpy(print_buf, "");
312 |
313 | /*
314 | printf("Hi there, there is nothing to configure yet\nBye..... :-)\n");
315 | fflush(NULL);
316 |
317 | SK_close(sock);
318 | */
319 | PC_interact(sock);
320 |
321 | pthread_exit((void *)0);
322 |
323 | } /* TH_do_config() */
324 |
325 | /* TH_hdl_signal() */
326 | /*++++++++++++++++++++++++++++++++++++++
327 |
328 | Handle signals.
329 |
330 | Changes the flags:
331 | do_nrtm
332 | do_update
333 | do_whoisd
334 |
335 | More:
336 | +html+ <PRE>
337 | Author:
338 | andrei
339 | +html+ </PRE>
340 | ++++++++++++++++++++++++++++++++++++++*/
341 | void TH_hdl_signal() {
342 | char print_buf[STR_M];
343 | sigset_t sset;
344 | int sigReceived;
345 |
346 | sigemptyset(&sset);
347 | sigaddset(&sset, SIGTERM);
348 | sigaddset(&sset, SIGINT);
349 | pthread_sigmask(SIG_BLOCK, &sset, NULL);
350 | // fprintf(stderr, "Signal handler installed\n");
351 |
352 | for(;;)
353 | {
354 | sigReceived=sigwait(&sset);
355 | sprintf(print_buf, "Signal received [%d]\n", sigReceived);
356 | log_print(print_buf); strcpy(print_buf, "");
357 | // fprintf(stderr, "Signal received [%d]\n", sigReceived);
358 | switch (sigReceived)
359 | {
360 | case SIGTERM:
361 | sprintf(print_buf, "%d", 0);
362 | CO_set_const("MI.do_nrtm", print_buf);
363 | sprintf(print_buf, "Stopping NRTM client\n");
364 | log_print(print_buf); strcpy(print_buf, "");
365 | // fprintf(stderr, "Stopping NRTM client (SIGTERM received)[%d]\n", CO_get_do_nrtm());
366 | break;
367 |
368 | case SIGINT:
369 | sprintf(print_buf, "%d", 0);
370 | CO_set_const("UD.do_update", print_buf);
371 | sprintf(print_buf, "Stopping updates\n");
372 | log_print(print_buf); strcpy(print_buf, "");
373 | // fprintf(stderr, "Stopping updates (SIGINT received)\n");
374 | pthread_exit((void *)0);
375 | break;
376 | }
377 | }
378 | } /* TH_hdl_signal() */
379 |
380 |
381 |
382 |
383 | /* main_thread() */
384 | /*++++++++++++++++++++++++++++++++++++++
385 |
386 | Waits for an incoming connection on the and spawns a new thread to handle it.
387 |
388 | void *arg Pointer to a struct containing the socket to talk to the client and
389 | the function to call depending on the incoming connection.
390 |
391 | More:
392 | +html+ <PRE>
393 | Author:
394 | ottrey
395 | joao
396 | +html+ </PRE>
397 | ++++++++++++++++++++++++++++++++++++++*/
398 | static void *main_thread(void *arg) {
399 | th_args *args = (th_args *)arg;
400 | pthread_t tid;
401 | pthread_attr_t attr;
402 | int connected_socket;
403 |
404 | while(1) {
405 |
406 | connected_socket = SK_accept_connection(args->sock);
407 |
408 | /* Start a new thread. */
409 |
410 | pthread_attr_init(&attr); /* initialize attr with default attributes */
411 | pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
412 | pthread_create(&tid, &attr, (void *(*)(void *))(args->function), (void *)connected_socket);
413 | }
414 |
415 | } /* main_thread() */
416 |
417 | /* TH_run() */
418 | /*++++++++++++++++++++++++++++++++++++++
419 |
420 | This is the routine that creates the main threads.
421 |
422 | int sock The socket to connect to.
423 | void * do_function The function to call for each type of service
424 |
425 | More:
426 | +html+ <PRE>
427 | Author:
428 | ottrey
429 | joao
430 | +html+ </PRE>
431 | ++++++++++++++++++++++++++++++++++++++*/
432 | void TH_run(int sock, void *do_function(void *)) {
433 | th_args *args;
434 | pthread_t tid;
435 | pthread_attr_t attr;
436 | char print_buf[STR_M];
437 |
438 | int connected_socket;
439 |
440 | // args = (th_args *)calloc(1,sizeof(th_args));
441 | dieif( wr_calloc((void **)&args,1,sizeof(th_args)) != UT_OK);
442 |
443 | args->function=do_function;
444 | args->sock=sock;
445 |
446 | /* pthread_mutex_init(&Whois_thread_count_lock,NULL); */
447 |
448 | if ( CO_get_max_threads() == 0 ) {
449 | sprintf(print_buf, "Running with no threads\n"); log_print(print_buf); strcpy(print_buf, "");
450 | connected_socket = SK_accept_connection(sock);
451 | PW_interact(connected_socket);
452 | }
453 | else {
454 | /* Start a new thread. */
455 | pthread_attr_init(&attr); /* initialize attr with default attributes */
456 | pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
457 | pthread_create(&tid, &attr, main_thread, (void *)args);
458 | }
459 |
460 | } /* TH_run() */
461 |
462 |
463 | /*++++++++++++++++++++++++++++++++++++++
464 |
465 | This is the routine that creates 1 main thread.
466 |
467 | int sock The socket to listen to.
468 | void * do_function The function to call for each type of service
469 |
470 | More:
471 | +html+ <PRE>
472 | Author:
473 | ottrey
474 | joao
475 | andrei
476 | +html+ </PRE>
477 | ++++++++++++++++++++++++++++++++++++++*/
478 | void TH_run1(int sock, void *do_function(void *) ) {
479 | pthread_t tid;
480 | pthread_attr_t attr;
481 |
482 | /* Start a new thread. */
483 | pthread_attr_init(&attr); /* initialize attr with default attributes */
484 | pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
485 | pthread_create(&tid, &attr, do_function, (void *)sock);
486 |
487 | } /* TH_run() */
488 |
489 |
490 | void TH_run2(void *function(void *)) {
491 | pthread_t tid;
492 | pthread_attr_t attr;
493 |
494 | /* Start a new thread. */
495 | pthread_attr_init(&attr); /* initialize attr with default attributes */
496 | pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
497 | pthread_create(&tid, &attr, function, (void *)0);
498 |
499 | } /* TH_run2() */