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