## modules/sk/sk_socket.c

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

## FUNCTIONS

This source file includes following functions.

1. SK_atoport
2. func_sigusr
3. SK_close
4. SK_getsock
5. SK_accept_connection
6. SK_read
7. SK_write
8. SK_gets
9. SK_puts
10. SK_putc
11. SK_getc
12. SK_getpeername
13. SK_getpeerip
14. SK_cd_puts
15. SK_cd_gets
16. SK_cd_close
17. SK_cd_printf
18. sk_watchdog
19. SK_watchstart
20. SK_watchstop
21. SK_watchkill
22. SK_watchexec
23. SK_watchclear

       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) {
         /* [<][>][^][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_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) {
         /* [<][>][^][v][top][bottom][index][help] */
     110   ER_dbg_va(FAC_SK, ASP_SK_GEN,"func_sigusr(%d) called", n);
     111 }
     112
     113 int SK_close(int socket) {
         /* [<][>][^][v][top][bottom][index][help] */
     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) {
         /* [<][>][^][v][top][bottom][index][help] */
     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) {
         /* [<][>][^][v][top][bottom][index][help] */
     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) {
         /* [<][>][^][v][top][bottom][index][help] */
     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) {
         /* [<][>][^][v][top][bottom][index][help] */
     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) {
         /* [<][>][^][v][top][bottom][index][help] */
     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) {
         /* [<][>][^][v][top][bottom][index][help] */
     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) {
         /* [<][>][^][v][top][bottom][index][help] */
     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) {
         /* [<][>][^][v][top][bottom][index][help] */
     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)
         /* [<][>][^][v][top][bottom][index][help] */
     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) {
         /* [<][>][^][v][top][bottom][index][help] */
     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) {
         /* [<][>][^][v][top][bottom][index][help] */
     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) {
         /* [<][>][^][v][top][bottom][index][help] */
     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) {
         /* [<][>][^][v][top][bottom][index][help] */
     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, ...)
         /* [<][>][^][v][top][bottom][index][help] */
     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)
         /* [<][>][^][v][top][bottom][index][help] */
     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)
         /* [<][>][^][v][top][bottom][index][help] */
     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)
         /* [<][>][^][v][top][bottom][index][help] */
     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)
         /* [<][>][^][v][top][bottom][index][help] */
     809 {
     810   condat->killthis = killthis;
     811 }
     812
     813 void
     814 SK_watchexec( sk_conn_st *condat, void *(*function)(void *) , void *args)
         /* [<][>][^][v][top][bottom][index][help] */
     815 {
     816   condat->execthis = function;
     817   condat->execargs = args;
     818 }
     819
     820 void
     821 SK_watchclear(sk_conn_st *condat)
         /* [<][>][^][v][top][bottom][index][help] */
     822 {
     823   condat->execthis = NULL;
     824   condat->execargs = NULL;
     825   condat->killthis = 0;
     826 }

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