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