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