## 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_init
18. func_sigusr
19. sk_watchdog
20. SK_watchstart
21. SK_watchstop
22. SK_watchkill
23. SK_watchexec
24. SK_watchclear

       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) {
         /* [<][>][^][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   /*  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) {
         /* [<][>][^][v][top][bottom][index][help] */
     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) {
         /* [<][>][^][v][top][bottom][index][help] */
     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) {
         /* [<][>][^][v][top][bottom][index][help] */
     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) {
         /* [<][>][^][v][top][bottom][index][help] */
     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) {
         /* [<][>][^][v][top][bottom][index][help] */
     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) {
         /* [<][>][^][v][top][bottom][index][help] */
     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) {
         /* [<][>][^][v][top][bottom][index][help] */
     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) {
         /* [<][>][^][v][top][bottom][index][help] */
     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) {
         /* [<][>][^][v][top][bottom][index][help] */
     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)
         /* [<][>][^][v][top][bottom][index][help] */
     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) {
         /* [<][>][^][v][top][bottom][index][help] */
     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) {
         /* [<][>][^][v][top][bottom][index][help] */
     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) {
         /* [<][>][^][v][top][bottom][index][help] */
     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) {
         /* [<][>][^][v][top][bottom][index][help] */
     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, ...)
         /* [<][>][^][v][top][bottom][index][help] */
     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)
         /* [<][>][^][v][top][bottom][index][help] */
     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) {
         /* [<][>][^][v][top][bottom][index][help] */
     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)
         /* [<][>][^][v][top][bottom][index][help] */
     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)
         /* [<][>][^][v][top][bottom][index][help] */
     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)
         /* [<][>][^][v][top][bottom][index][help] */
     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)
         /* [<][>][^][v][top][bottom][index][help] */
     845 {
     846   condat->killthis = killthis;
     847 }
     848
     849 void
     850 SK_watchexec( sk_conn_st *condat, void *(*function)(void *) , void *args)
         /* [<][>][^][v][top][bottom][index][help] */
     851 {
     852   condat->execthis = function;
     853   condat->execargs = args;
     854 }
     855
     856 void
     857 SK_watchclear(sk_conn_st *condat)
         /* [<][>][^][v][top][bottom][index][help] */
     858 {
     859   condat->execthis = NULL;
     860   condat->execargs = NULL;
     861   condat->killthis = 0;
     862 }

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