## 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] */