1 | /*************************************** 2 | $Revision: 1.9 $ 3 | 4 | Example code: A socket module. 5 | 6 | Status: NOT REVUED, NOT TESTED 7 | 8 | +html+ <DL COMPACT> 9 | +html+ <DT>Online References: 10 | +html+ <DD><UL> 11 | +html+ <LI>Adapted from <A HREF="http://www.ibrado.com/sock-faq/sfaq.html#faq65">sample source code</A>. 12 | +html+ </UL> 13 | +html+ </DL> 14 | +html+ <PRE> 15 | +html+ </PRE> 16 | 17 | ******************/ /****************** 18 | Modification History: 19 | ottrey (08/03/1999) Created from sockhelp.c. 20 | ottrey (08/03/1998) Heavily butchered. 21 | joao (22/06/1999) Modified socket creation and accepts. 22 | ******************/ /****************** 23 | REMINDER: PUT THE PROPER COPYRIGHT NOTICE HERE 24 | ***************************************/ 25 | #include <arpa/inet.h> 26 | #include "sk.h" 27 | #include "constants.h" 28 | #include "stubs.h" 29 | 30 | #include "iproutines.h" 31 | #include "memwrap.h" 32 | 33 | #include <pthread.h> 34 | 35 | extern int h_errno; 36 | 37 | 38 | /*+ String sizes +*/ 39 | #define STR_S 63 40 | #define STR_M 255 41 | #define STR_L 1023 42 | #define STR_XL 4095 43 | #define STR_XXL 16383 44 | 45 | /* SK_atoport() */ 46 | /*++++++++++++++++++++++++++++++++++++++ 47 | Take a service name, and a service type, and return a port number. If the 48 | service name is not found, it tries it as a decimal number. The number 49 | returned is byte ordered for the network. 50 | 51 | char *service Service name (or port number). 52 | 53 | char *proto Protocol (eg "tcp"). 54 | 55 | More: 56 | +html+ <PRE> 57 | Authors: 58 | ottrey 59 | 60 | +html+ </PRE><DL COMPACT> 61 | +html+ <DT>Online References: 62 | +html+ <DD><UL> 63 | +html+ </UL></DL> 64 | 65 | ++++++++++++++++++++++++++++++++++++++*/ 66 | int SK_atoport(const char *service, const char *proto) { 67 | int port; 68 | long int lport; 69 | struct servent *serv; 70 | char *errpos; 71 | struct servent result; 72 | char buffer[STR_XXL]; 73 | 74 | /* First try to read it from /etc/services */ 75 | 76 | #ifdef _LINUX 77 | if(getservbyname_r(service, proto, &result, buffer, sizeof(buffer), &serv) < 0) serv = NULL; 78 | #else 79 | serv = getservbyname_r(service, proto, &result, buffer, sizeof(buffer)); 80 | #endif 81 | 82 | if (serv != NULL) 83 | port = serv->s_port; 84 | else { /* Not in services, maybe a number? */ 85 | lport = strtol(service,&errpos,0); 86 | if ( (errpos[0] != 0) || (lport < 1) || (lport > 65535) ) 87 | return -1; /* Invalid port address */ 88 | port = htons(lport); 89 | } 90 | return port; 91 | } /* SK_atoport() */ 92 | 93 | 94 | /* SK_close() */ 95 | /*++++++++++++++++++++++++++++++++++++++ 96 | 97 | More: 98 | +html+ <PRE> 99 | Authors: 100 | ottrey 101 | 102 | +html+ </PRE><DL COMPACT> 103 | +html+ <DT>Online References: 104 | +html+ <DD><UL> 105 | +html+ </UL></DL> 106 | 107 | ++++++++++++++++++++++++++++++++++++++*/ 108 | int SK_close(int socket) { 109 | ER_dbg_va(FAC_SK, ASP_SK_GEN, "Closing socket... %d", socket); 110 | 111 | return close(socket); 112 | } 113 | 114 | /* SK_getsock() */ 115 | /*++++++++++++++++++++++++++++++++++++++ 116 | 117 | This function creates a socket and binds to it 118 | 119 | int SK_getsock The new socket 120 | 121 | int socket_type SOCK_STREAM or SOCK_DGRAM (TCP or UDP sockets) 122 | 123 | u_short port The port to listen on. Remember that ports < 1024 are 124 | reserved for the root user. Must be passed in network byte 125 | order (see "man htons"). 126 | 127 | uint32_t bind_address Address to bind to, in network order. 128 | More: 129 | +html+ <PRE> 130 | Authors: 131 | ottrey 132 | joao 133 | 134 | +html+ </PRE><DL COMPACT> 135 | +html+ <DT>Online References: 136 | +html+ <DD><UL> 137 | +html+ </UL></DL> 138 | 139 | ++++++++++++++++++++++++++++++++++++++*/ 140 | int SK_getsock(int socket_type, u_short port, uint32_t bind_address) { 141 | struct sockaddr_in address; 142 | int listening_socket; 143 | int reuse_addr = 1; 144 | 145 | /* Setup internet address information. 146 | This is used with the bind() call */ 147 | memset((char *) &address, 0, sizeof(address)); 148 | address.sin_family = AF_INET; 149 | address.sin_port = port; 150 | address.sin_addr.s_addr = bind_address; 151 | 152 | /* Map all of the signals and exit routine */ 153 | 154 | listening_socket = socket(AF_INET, socket_type, 0); 155 | if (listening_socket < 0) { 156 | perror("socket"); 157 | exit(EXIT_FAILURE); 158 | } 159 | 160 | setsockopt(listening_socket, SOL_SOCKET, SO_REUSEADDR, (void *)&reuse_addr, sizeof(reuse_addr)); 161 | 162 | if (bind(listening_socket, (struct sockaddr *) &address, sizeof(address)) < 0) { 163 | perror("bind"); 164 | close(listening_socket); 165 | exit(EXIT_FAILURE); 166 | } 167 | 168 | 169 | if (socket_type == SOCK_STREAM) { 170 | listen(listening_socket, 5); /* Queue up to five connections before 171 | having them automatically rejected. */ 172 | } 173 | 174 | return listening_socket; 175 | } /* SK_getsock() */ 176 | 177 | /*++++++++++++++++++++++++++++++++++++++ 178 | 179 | Wait for an incoming connection on the specified socket 180 | 181 | int SK_accept_connection The socket for communicating to the client 182 | 183 | int listening_socket The socket that the server is bound to 184 | 185 | More: 186 | +html+ <PRE> 187 | Authors: 188 | joao 189 | +html+ </PRE> 190 | ++++++++++++++++++++++++++++++++++++++*/ 191 | int SK_accept_connection(int listening_socket) { 192 | int connected_socket = -1; 193 | 194 | while(connected_socket < 0) { 195 | 196 | ER_dbg_va(FAC_SK, ASP_SK_GEN, 197 | "Going to accept connections on socket : %d",listening_socket); 198 | 199 | /* XXX joao - ? - why is this here? 200 | fflush(NULL); 201 | */ 202 | 203 | connected_socket = accept(listening_socket, NULL, NULL); 204 | if (connected_socket < 0) { 205 | /* Either a real error occured, or blocking was interrupted for 206 | some reason. Only abort execution if a real error occured. */ 207 | if (errno != EINTR) { 208 | perror("accept"); 209 | close(listening_socket); 210 | return(-1); 211 | /* no exit, just return with error */ 212 | } else { 213 | continue; /* don't return - do the accept again */ 214 | } 215 | } 216 | } 217 | 218 | ER_dbg_va(FAC_SK, ASP_SK_GEN, "client connected on socket %d", 219 | connected_socket 220 | ); 221 | 222 | return connected_socket; 223 | } 224 | 225 | /* SK_read() */ 226 | /*++++++++++++++++++++++++++++++++++++++ 227 | 228 | This is just like the read() system call, except that it will make 229 | sure that all your data goes through the socket. 230 | 231 | int SK_read The number of bytes read. 232 | 233 | int sockfd The socket file descriptor. 234 | 235 | char *buf The buffer to be read from the socket. 236 | 237 | size_t count The number of bytes in the buffer. 238 | 239 | More: 240 | +html+ <PRE> 241 | Authors: 242 | ottrey 243 | +html+ </PRE> 244 | ++++++++++++++++++++++++++++++++++++++*/ 245 | int SK_read(int sockfd, char *buf, size_t count) { 246 | size_t bytes_read = 0; 247 | int this_read; 248 | 249 | while (bytes_read < count) { 250 | do 251 | this_read = read(sockfd, buf, count - bytes_read); 252 | while ( (this_read < 0) && (errno == EINTR) ); 253 | if (this_read < 0) 254 | return this_read; 255 | else if (this_read == 0) 256 | return bytes_read; 257 | bytes_read += this_read; 258 | buf += this_read; 259 | } 260 | 261 | return count; 262 | 263 | } /* SK_read() */ 264 | 265 | 266 | /* SK_write() */ 267 | /*++++++++++++++++++++++++++++++++++++++ 268 | 269 | This is just like the write() system call, accept that it will 270 | make sure that all data is transmitted. 271 | 272 | int sockfd The socket file descriptor. 273 | 274 | char *buf The buffer to be written to the socket. 275 | 276 | size_t count The number of bytes in the buffer. 277 | 278 | More: 279 | +html+ <PRE> 280 | Authors: 281 | ottrey 282 | 283 | +html+ </PRE><DL COMPACT> 284 | +html+ <DT>Online References: 285 | +html+ <DD><UL> 286 | +html+ </UL></DL> 287 | 288 | ++++++++++++++++++++++++++++++++++++++*/ 289 | int SK_write(int sockfd, const char *buf, size_t count) { 290 | size_t bytes_sent = 0; 291 | int this_write; 292 | 293 | 294 | ER_dbg_va(FAC_SK, ASP_SK_WRIT, 295 | "SK_write = { sockfd=[%d], buf=[%s], count=[%d]", 296 | sockfd, buf, count); 297 | 298 | while (bytes_sent < count) { 299 | do 300 | this_write = write(sockfd, buf, count - bytes_sent); 301 | while ( (this_write < 0) && (errno == EINTR) ); 302 | if (this_write <= 0) 303 | return this_write; 304 | bytes_sent += this_write; 305 | buf += this_write; 306 | } 307 | return count; 308 | } /* SK_write() */ 309 | 310 | 311 | /* SK_gets() */ 312 | /*++++++++++++++++++++++++++++++++++++++ 313 | 314 | This function reads from a socket, until it recieves a linefeed 315 | character. It fills the buffer "str" up to the maximum size "count". 316 | 317 | int SK_gets The total_count of bytes read. 318 | 319 | int sockfd The socket file descriptor. 320 | 321 | char *str The buffer to be written from the socket. 322 | 323 | size_t count The number of bytes in the buffer. 324 | 325 | More: 326 | +html+ <PRE> 327 | Authors: 328 | ottrey 329 | 330 | Side Effects: 331 | This function will return -1 if the socket is closed during the read operation. 332 | 333 | Note that if a single line exceeds the length of count, the extra data 334 | will be read and discarded! You have been warned. 335 | 336 | To Do: 337 | Capture the control-c properly! 338 | 339 | +html+ </PRE> 340 | 341 | ++++++++++++++++++++++++++++++++++++++*/ 342 | int SK_gets(int sockfd, char *str, size_t count) { 343 | int bytes_read; 344 | int total_count = 0; 345 | char *current_position; 346 | char last_read = 0; 347 | 348 | int control_c = 0; 349 | 350 | current_position = str; 351 | while (last_read != 10) { 352 | 353 | 354 | 355 | bytes_read = read(sockfd, &last_read, 1); 356 | if (bytes_read <= 0) { 357 | /* The other side may have closed unexpectedly */ 358 | return SK_DISCONNECT; 359 | /* Is this effective on other platforms than linux? */ 360 | } 361 | if ( (total_count < count) && (last_read != 10) && (last_read !=13) ) { 362 | *current_position = last_read; 363 | current_position++; 364 | total_count++; 365 | } 366 | 367 | if (last_read == -1) { 368 | bytes_read = read(sockfd, &last_read, 1); 369 | if (last_read == -12) { 370 | ER_dbg_va(FAC_SK, ASP_SK_GEN,"Client pressed Control-c"); 371 | control_c = 1; 372 | ER_dbg_va(FAC_SK, ASP_SK_GEN,"returning SK_INTERRUPT"); 373 | return SK_INTERRUPT; 374 | } 375 | } 376 | } 377 | if (count > 0) { 378 | *current_position = 0; 379 | } 380 | 381 | return total_count; 382 | 383 | } /* SK_gets() */ 384 | 385 | 386 | /* SK_puts() */ 387 | /*++++++++++++++++++++++++++++++++++++++ 388 | 389 | This function writes a character string out to a socket. 390 | 391 | int SK_puts The total_count of bytes written, 392 | or errors (represented as negative numbers) 393 | 394 | int sockfd The socket file descriptor. 395 | 396 | char *str The buffer to be written from the socket. 397 | 398 | More: 399 | +html+ <PRE> 400 | Authors: 401 | ottrey 402 | 403 | Side Effects: 404 | This function will return -1 if the socket is closed during the write operation. 405 | 406 | Note that if a single line exceeds the length of count, the extra data 407 | will be read and discarded! You have been warned. 408 | 409 | +html+ </PRE> 410 | 411 | ++++++++++++++++++++++++++++++++++++++*/ 412 | int SK_puts(int sockfd, const char *str) { 413 | 414 | return SK_write(sockfd, str, strlen(str)); 415 | 416 | } /* SK_puts() */ 417 | 418 | /* SK_putc() */ 419 | /*++++++++++++++++++++++++++++++++++++++ 420 | 421 | int SK_putc This function writes a single character out to a socket. 422 | 423 | int sockfd socket 424 | char ch character 425 | 426 | return number of chars written 427 | 428 | ++++++++++++++++++++++++++++++++++++++*/ 429 | int SK_putc(int sockfd, char ch) { 430 | return SK_write(sockfd, &ch, 1); 431 | }/* SK_putc() */ 432 | 433 | /*++++++++++++++++++++++++++++++++++++++ 434 | 435 | This function reads a single character from a socket. 436 | 437 | returns EOF when no character can be read. 438 | 439 | ++++++++++++++++++++++++++++++++++++++*/ 440 | int SK_getc(int sockfd) { 441 | char ch; 442 | 443 | if( read(sockfd, &ch, 1) <= 0 ) { 444 | return EOF; 445 | } 446 | else { 447 | return ch; 448 | } 449 | }/* SK_getc() */ 450 | 451 | /* SK_getpeername() */ 452 | /*++++++++++++++++++++++++++++++++++++++ 453 | 454 | This function will tell you who is at the other end of a connected stream socket. 455 | XXX It's not working. 456 | XXX ? MB it is... 457 | 458 | int sockfd The socket file descriptor. 459 | 460 | More: 461 | +html+ <PRE> 462 | Authors: 463 | ottrey 464 | +html+ </PRE> 465 | 466 | ++++++++++++++++++++++++++++++++++++++*/ 467 | char *SK_getpeername(int sockfd) 468 | { 469 | char *hostaddress=NULL; 470 | struct sockaddr_in addr_in; 471 | int namelen=sizeof(addr_in); 472 | 473 | if (getpeername(sockfd, (struct sockaddr *)&addr_in, &namelen) != -1) { 474 | 475 | dieif( wr_malloc((void **)&hostaddress, 16) != UT_OK); 476 | 477 | strcpy(hostaddress, inet_ntoa(addr_in.sin_addr)); /* XXX MT-UNSAFE */ 478 | } 479 | 480 | return hostaddress; 481 | 482 | } /* SK_getpeername() */ 483 | 484 | /* SK_getpeerip */ 485 | int SK_getpeerip(int sockfd, ip_addr_t *ip) { 486 | struct sockaddr_in addr_in; 487 | int namelen=sizeof(addr_in); 488 | int ret=-1; 489 | 490 | memset(& addr_in, 0, sizeof(struct sockaddr_in)); 491 | 492 | if (getpeername(sockfd, (struct sockaddr *)(& addr_in), &namelen) != -1) { 493 | ret=0; 494 | IP_addr_s2b(ip, &addr_in, namelen); 495 | } 496 | 497 | return ret; 498 | } 499 | 500 | /*------------------------------------------------------------------- 501 | * CD varieties of the functions: broken connections get registered 502 | * in the connection structure within the query environment 503 | * as side effects. 504 | * -----------------------------------------------------------------*/ 505 | 506 | /* SK_cd_puts() */ 507 | /*++++++++++++++++++++++++++++++++++++++ 508 | 509 | This function writes a character string out to a socket. 510 | 511 | int SK_qe_puts The total_count of bytes written, 512 | or errors (represented as negative numbers) 513 | 514 | sk_conn_st *condat connection data 515 | 516 | char *str The buffer to be written from the socket. 517 | 518 | More: 519 | if the connection structure has bad status for this connection 520 | from previous calls, no write will be attempted. 521 | 522 | +html+ <PRE> 523 | Authors: 524 | marek 525 | 526 | Side Effects: 527 | broken connections get registered 528 | in the connection structure within the query environment 529 | 530 | +html+ </PRE> 531 | 532 | ++++++++++++++++++++++++++++++++++++++*/ 533 | int SK_cd_puts(sk_conn_st *condat, const char *str) { 534 | int res=SK_puts(condat->sock, str); 535 | 536 | if( res < 0 ){ 537 | /* set the corresponding rtc flag */ 538 | condat->rtc |= (-res); 539 | 540 | switch( - res ) { 541 | /* dont know what to do and how to log */ 542 | case SK_DISCONNECT: 543 | case SK_INTERRUPT: 544 | /*("Thread received a control-c\n");*/ 545 | case SK_TIMEOUT: 546 | /*("Reading timed out\n");*/ 547 | break; 548 | default: 549 | /* unexpected error code. bail out */ 550 | die; 551 | } 552 | } 553 | return res; 554 | } /* SK_cd_puts() */ 555 | 556 | /* SK_cd_gets() */ 557 | /*++++++++++++++++++++++++++++++++++++++ 558 | 559 | Wrapper around SK_gets. 560 | 561 | int SK_cd_gets The total_count of bytes read, 562 | or errors (represented as negative numbers) 563 | 564 | sk_conn_st *condat connection data 565 | 566 | char *str The buffer to be written from the socket. 567 | 568 | More: 569 | if the connection structure has bad status for this connection 570 | from previous calls, no write will be attempted. 571 | 572 | +html+ <PRE> 573 | Authors: 574 | marek 575 | 576 | Side Effects: 577 | broken connections get registered 578 | in the connection structure within the query environment 579 | 580 | +html+ </PRE> 581 | 582 | ++++++++++++++++++++++++++++++++++++++*/ 583 | int SK_cd_gets(sk_conn_st *condat, char *str, size_t count) { 584 | fd_set rset; 585 | struct timeval *ptm = & condat->rd_timeout; 586 | int readcount = 0; 587 | 588 | memset( str, 0, count); 589 | FD_ZERO( &rset ); 590 | FD_SET( condat->sock, &rset ); 591 | 592 | if( ptm->tv_sec == 0 && ptm->tv_usec == 0) { /* if timeout undefined, 593 | do blocking I/O */ 594 | ptm = NULL; 595 | } 596 | 597 | do { 598 | char buf[2]; 599 | int sel = select( (condat->sock)+1, &rset, NULL, NULL, ptm); 600 | 601 | dieif(sel < 0); /* we don't expect problems */ 602 | 603 | if( sel == 0 ) { 604 | condat->rtc |= SK_TIMEOUT; 605 | break; 606 | } 607 | 608 | else { 609 | if(read( condat->sock, buf, 1 )==0)break; 610 | str[readcount] = buf[0]; 611 | readcount++; 612 | if( buf[0] == '\n' ) { 613 | break; 614 | } 615 | } 616 | } while( readcount < count ); 617 | 618 | return readcount; 619 | 620 | } /* SK_cd_gets() */ 621 | 622 | 623 | int SK_cd_close(sk_conn_st *condat) { 624 | return SK_close(condat->sock); 625 | } /* SK_cd_close() */ 626 | 627 | 628 | /* print to condat like printf 629 | 630 | by marek 631 | */ 632 | int SK_cd_printf(sk_conn_st *condat, char *txt, ...) 633 | { 634 | #define SKBUFLEN 2047 635 | va_list ap; 636 | char buffer[SKBUFLEN+1]; 637 | int len; 638 | char *newbuf = NULL; 639 | char *finalbuf = buffer; /* points to where the text REALLY is */ 640 | 641 | /* vsnprintf returns the number of character it WOULD write if it could. 642 | So we assume the buffer to be of adequate size for most cases, 643 | and if it isn't, then we allocate to newbuf and call v*printf again 644 | */ 645 | va_start(ap, txt); 646 | len = vsnprintf(buffer, SKBUFLEN, txt, ap); 647 | va_end(ap); 648 | 649 | if( len > SKBUFLEN ) { 650 | dieif(!NOERR(wr_malloc( (void **)& newbuf, len+1))); 651 | 652 | va_start(ap, txt); 653 | vsnprintf(newbuf, len, txt, ap); 654 | va_end(ap); 655 | 656 | finalbuf = newbuf; 657 | } 658 | /* terminate */ 659 | finalbuf[len] = 0; 660 | 661 | /* reuse len */ 662 | len = SK_cd_puts(condat, finalbuf); 663 | 664 | if(newbuf != NULL) { 665 | wr_free(newbuf); 666 | } 667 | 668 | return len; 669 | } 670 | 671 | /* =========================== watchdog =========================== 672 | by marek 673 | */ 674 | 675 | static pthread_key_t sk_watch_tsd; 676 | static pthread_once_t sk_init_once = PTHREAD_ONCE_INIT; 677 | 678 | static void sk_real_init(void) 679 | { 680 | dieif( pthread_key_create( &sk_watch_tsd, NULL) != 0 ); 681 | } 682 | 683 | void SK_init(void) 684 | { 685 | /* can be called only once */ 686 | pthread_once( &sk_init_once, sk_real_init); 687 | } 688 | 689 | /* sk_watchdog signal handler */ 690 | static void func_sigusr(int n) { 691 | #if 0 692 | /* just for debugging - we don't check the value here */ 693 | int *tsd_flag = (int *) pthread_getspecific(sk_watch_tsd); 694 | #endif 695 | 696 | ER_dbg_va(FAC_SK, ASP_SK_GEN,"func_sigusr(%d) called", n); 697 | 698 | /* set a thread-specific flag that the handler was invoked */ 699 | 700 | pthread_setspecific(sk_watch_tsd, (void *)1 ); 701 | } 702 | 703 | /* sk_watchdog - started as a separate thread. 704 | 705 | selects on the given socket; discards all input. 706 | whenever it sees end of file (socket closed), it 707 | * sets a corresponding flag in the condat structure, 708 | * kills a thread designated to be killed (by SK_watchkill) 709 | 710 | by marek; 711 | */ 712 | static 713 | void *sk_watchdog(void *arg) 714 | { 715 | sk_conn_st *condat = (sk_conn_st *) arg; 716 | int nready; 717 | int n; 718 | fd_set rset; 719 | char buff[STR_S]; 720 | int socket = condat->sock; 721 | sigset_t sset; 722 | struct sigaction act; 723 | 724 | struct timeval timeout = { 1, 0 }; /* it's a timeout of 1 second */ 725 | 726 | FD_ZERO(&rset); 727 | FD_SET(socket, &rset); 728 | 729 | sigemptyset(&sset); 730 | sigaddset(&sset, SIGUSR1); 731 | 732 | act.sa_handler = func_sigusr; 733 | act.sa_flags = 0; 734 | dieif(sigaction(SIGUSR1, &act, NULL) != 0); 735 | 736 | /* XXX in fact, it's unblocked already. Should be blocked on startup */ 737 | dieif(pthread_sigmask(SIG_UNBLOCK, &sset, NULL) != 0); 738 | 739 | /* clear the handler's flag */ 740 | pthread_setspecific(sk_watch_tsd, NULL); 741 | 742 | /* now ready for signal */ 743 | pthread_mutex_unlock( & condat->watchmutex ); 744 | 745 | /* hey, viva threaded signal handling! There is no way for select 746 | to unblock a blocked signal, It must be done by "hand" (above). 747 | 748 | Consequently, every once in a while, the signal will be delivered 749 | before the select starts :-/. So, we have to introduce a timeout 750 | for select and check if the signal was delivered anyway....aARGH!!! 751 | 752 | This adds a <timeout interval> to unlucky queries, about 0.1% of all. 753 | */ 754 | 755 | while ((nready=select(socket+1, &rset, NULL, NULL, &timeout))!=-1) { 756 | 757 | ER_dbg_va(FAC_SK, ASP_SK_GEN,"select returned %d", nready); 758 | 759 | /* don't even try to read if we have been killed */ 760 | if( errno == EINTR || pthread_getspecific(sk_watch_tsd) != NULL ) { 761 | break; 762 | } 763 | 764 | /* retry if the timeout has triggered */ 765 | if( nready == 0 ) { 766 | continue; 767 | } 768 | 769 | /* There was some input or client half of connection was closed */ 770 | /* Check for the latter */ 771 | if (( n=read(socket, buff, sizeof(buff))) == 0) { 772 | /* Connection was closed by client */ 773 | /* Now send a cancellation request to the whois thread. */ 774 | /* mysql thread will be terminated by thread cleanup routine */ 775 | 776 | /* call the actions: kill and exec (the SK_ functions called 777 | check if the action is defined. Will set the RTC flag on condat 778 | */ 779 | SK_watchtrigger(condat); 780 | 781 | /* quit */ 782 | break; 783 | } 784 | /* Otherwise dump input and continue */ 785 | 786 | } 787 | 788 | /* Exit the watchdog thread, passing NULL as we don't expect a join */ 789 | pthread_exit(NULL); 790 | 791 | /* oh yes. Shouldn't compilers _analyze_ library functions ? */ 792 | return NULL; 793 | } 794 | /* SK_watchstart 795 | 796 | starts sk_watchdog thread unless already started, 797 | and registers its threadid in the condat structure 798 | 799 | dies if watchdog already running 800 | */ 801 | er_ret_t 802 | SK_watchstart(sk_conn_st *condat) 803 | { 804 | dieif( condat->watchdog != 0 ); 805 | 806 | /* init the mutex in locked state, watchdog will unlock it when 807 | it's ready for signal */ 808 | pthread_mutex_init( & condat->watchmutex, NULL ); 809 | pthread_mutex_lock( & condat->watchmutex ); 810 | 811 | pthread_create(&condat->watchdog, NULL, sk_watchdog, (void *) condat ); 812 | 813 | return SK_OK; 814 | } 815 | 816 | 817 | /* SK_watchstop 818 | 819 | stops sk_watchdog thread if it is registered in the connection struct 820 | */ 821 | er_ret_t 822 | SK_watchstop(sk_conn_st *condat) 823 | { 824 | void *res; 825 | 826 | if(condat->watchdog > 0) { 827 | int ret; 828 | 829 | /* wait until the watchdog is ready for signal */ 830 | pthread_mutex_lock( & condat->watchmutex ); 831 | 832 | ret = pthread_kill(condat->watchdog, SIGUSR1); 833 | 834 | ret = pthread_join(condat->watchdog, &res); 835 | 836 | pthread_mutex_destroy( & condat->watchmutex ); 837 | condat->watchdog = 0; 838 | } 839 | return SK_OK; 840 | } 841 | 842 | /* SK_watchkill 843 | 844 | sets the threadid of the thread to be killed by watchdog 845 | 0 means dont kill anything 846 | */ 847 | void 848 | SK_watch_setkill(sk_conn_st *condat, pthread_t killthis) 849 | { 850 | condat->killthis = killthis; 851 | } 852 | 853 | void 854 | SK_watch_setexec( sk_conn_st *condat, void *(*function)(void *) , void *args) 855 | { 856 | condat->execthis = function; 857 | condat->execargs = args; 858 | } 859 | 860 | void 861 | SK_watch_setclear(sk_conn_st *condat) 862 | { 863 | condat->execthis = NULL; 864 | condat->execargs = NULL; 865 | condat->killthis = 0; 866 | } 867 | 868 | /* call the function to be called if defined */ 869 | void 870 | SK_watchexec(sk_conn_st *condat) 871 | { 872 | /* set the reason-to-close flag on this connection */ 873 | condat->rtc |= SK_INTERRUPT; 874 | 875 | if( condat->execthis != NULL ) { 876 | condat->execthis(condat->execargs); 877 | } 878 | } 879 | 880 | /* cancel the thread to be cancelled if defined */ 881 | void 882 | SK_watchkill(sk_conn_st *condat) { 883 | 884 | /* set the reason-to-close flag on this connection */ 885 | condat->rtc |= SK_INTERRUPT; 886 | 887 | /* cancel thread if defined */ 888 | if( condat->killthis != 0 ) { 889 | pthread_cancel(condat->killthis); 890 | /* The only possible error is ESRCH, so we do not care about it*/ 891 | } 892 | } 893 | 894 | 895 | void SK_watchtrigger(sk_conn_st *condat) 896 | { 897 | SK_watchkill(condat); 898 | SK_watchexec(condat); 899 | 900 | }