modules/sk/sk_socket.c

/* [<][>]
[^][v][top][bottom][index][help] */

FUNCTIONS

This source file includes following functions.
  1. SK_atoport
  2. SK_close
  3. SK_getsock
  4. SK_accept_connection
  5. SK_read
  6. SK_write
  7. SK_gets
  8. SK_puts
  9. SK_putc
  10. SK_getc
  11. SK_getpeername
  12. SK_getpeerip
  13. SK_cd_puts
  14. SK_cd_gets
  15. SK_cd_close
  16. SK_cd_printf
  17. sk_real_init
  18. SK_init
  19. func_sigusr
  20. sk_watchdog
  21. SK_watchstart
  22. SK_watchstop
  23. SK_watch_setkill
  24. SK_watch_setexec
  25. SK_watch_setclear
  26. SK_watchexec
  27. SK_watchkill
  28. SK_watchtrigger

   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) {
     /* [<][>][^][v][top][bottom][index][help] */
  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) {
     /* [<][>][^][v][top][bottom][index][help] */
 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) {
     /* [<][>][^][v][top][bottom][index][help] */
 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) {
     /* [<][>][^][v][top][bottom][index][help] */
 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) {
     /* [<][>][^][v][top][bottom][index][help] */
 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) {
     /* [<][>][^][v][top][bottom][index][help] */
 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) {
     /* [<][>][^][v][top][bottom][index][help] */
 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) {
     /* [<][>][^][v][top][bottom][index][help] */
 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) {
     /* [<][>][^][v][top][bottom][index][help] */
 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) {
     /* [<][>][^][v][top][bottom][index][help] */
 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) 
     /* [<][>][^][v][top][bottom][index][help] */
 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) {
     /* [<][>][^][v][top][bottom][index][help] */
 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) {
     /* [<][>][^][v][top][bottom][index][help] */
 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) {
     /* [<][>][^][v][top][bottom][index][help] */
 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) {
     /* [<][>][^][v][top][bottom][index][help] */
 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, ...)
     /* [<][>][^][v][top][bottom][index][help] */
 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)
     /* [<][>][^][v][top][bottom][index][help] */
 679 {
 680   dieif( pthread_key_create( &sk_watch_tsd, NULL) != 0 );
 681 }
 682 
 683 void  SK_init(void)
     /* [<][>][^][v][top][bottom][index][help] */
 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) {
     /* [<][>][^][v][top][bottom][index][help] */
 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)
     /* [<][>][^][v][top][bottom][index][help] */
 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)
     /* [<][>][^][v][top][bottom][index][help] */
 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)
     /* [<][>][^][v][top][bottom][index][help] */
 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)
     /* [<][>][^][v][top][bottom][index][help] */
 849 {
 850   condat->killthis = killthis;
 851 }
 852 
 853 void
 854 SK_watch_setexec( sk_conn_st *condat, void *(*function)(void *) , void *args)
     /* [<][>][^][v][top][bottom][index][help] */
 855 {
 856   condat->execthis = function;
 857   condat->execargs = args;
 858 }
 859 
 860 void 
 861 SK_watch_setclear(sk_conn_st *condat) 
     /* [<][>][^][v][top][bottom][index][help] */
 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) 
     /* [<][>][^][v][top][bottom][index][help] */
 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) {
     /* [<][>][^][v][top][bottom][index][help] */
 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) 
     /* [<][>][^][v][top][bottom][index][help] */
 896 {
 897      SK_watchkill(condat);
 898      SK_watchexec(condat);
 899      
 900 }

/* [<][>][^][v][top][bottom][index][help] */