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() */